基本概念
在没有Spring之前,程序是通过public UserService user = new UserService()的形式,来给一个变量赋予引用值,user变量定义后就可以直接user.xxx()的来调用方法.
在有Spring之后,可以直接使用public UserService user的形式给来定义变量,而省略new UserService()这一部分,这部分由Spring来进行.
由Spring创建对象,称其为"控制反转",Spring创建对象的过程中,发现对象里面还有一个成员变量需要赋值,赋值的过程称为"依赖注入".
控制反转
简称为IOC,英文全称:Inversion of Control,为什么原本自己new一个对象
使用注解
告诉了Spring大佬new哪个对象后,如果对象里面有成员变量,还得告诉大佬,得给这个成员变量赋值,具体XML实例如下:
<bean id="mainUI" class="com.jungle.www.controller.MainUI">
<property name="jungle" ref="userService"/>
</bean>
<bean id="userService" class="com.jungle.www.service.serviceimp.UserServiceImpl">
</bean>
<!--
bean标签,就是用来告诉Spring创建哪个对象
"id" 指定对象名,
"class" 是类的全路径,写哪个类,就会创建哪个类的对象.
property标签,是告诉Spring大佬,创建的对象还有成员变量需要大佬赋值
"name" 需要赋值的成员变量名,Spring给成员变量赋值时,是通过setter 方法来赋值的,所以得给成员变量弄一个setter方法
"ref"代表引用亨达代理申请www.kaifx.cn/broker/hantecglobal.html其他bean的id名所具有的值
这里面有两个bean,所以创建了两个对象,分别名叫:mainUI和userService,其中mainUI实例里有一个叫jungle的成员变量,这个成员变量的值是引用了userService,上述的配置,等同于以下:
public void MainUI{
private jungle = new UserServiceImpl();
}
上面的例子里的成员变量,是引用类型,也就是一个对象,那么基本数据类型又如何解决赋值问题?集合又怎样解决赋值问题?系统的归纳如下:
属性赋值
value注入基本类型
<bean id="mainUI" class="com.MainUI">
<property name="str" value="李白"/>
</bean>
<!--
//上面的效果,创建了com.MainUI类的名叫mainUI的实例,并且给里面的str成员变量赋值为 李白
public void MainUI{
private String str;
//setter方法省略
}
//下面的实例也是同理
ref 注入已有的bean
官方源码有一句话:The name of the property, following JavaBean naming conventions,意思就是属性的名称,这里就把bean标签的id当做属性的的名称就行了
List\Set\Map
<property name="list">
<list>
<value>J</value>
<value>G</value>
</list>
</property>
<property name="set">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
</set>
</property>
<property name="map">
<map>
<entry key="dock" value="yellow"/>
</map>
</property>
上面通过bean标签来实例化对象时,默认采用的是无参构造来进行实例化,还有其他几种方法,也需要知道以下,下面总结一下:
bean的实例化
默认构造器实例化
<bean id="mainUI" class="com.jungle.com.MainUI">
效果:创建了com.jungle.com.MainUI类的名叫mainUI的实例
注意:需要com.jungle.com.MainUI类里具有无参构造!
静态工厂实例化
<bean id="today" class="com.jungle.com.service" factory-method="getObject"/>
效果:通过com.jungle.com.service类的名叫getObject的静态方法,创建一个名叫today的实例
实例工厂实例化
//Factory类
public class Factory {
public Robot getRobot(){
return new Robot();
}
}
//Robot类
public class Robot {
public void say(){
System.out.println("i am a robot");
}
}
<!--XML-->
<bean id="robot" factory-bean="factory" factory-method="getRobot"/>
<bean id="factory" class="com.Factory"/>
说明:
第一个bean
id:以后读取的时候,就是读取这个id来得到对象
factory-bean:指定生产者
factory-method:指定生产者所使用的方法
第二个bean:创建一个com.Factory类的叫factory的对象
//测试
public static void main( String[] args )
{
ClassPathXmlApplicationContext cpac =
new ClassPathXmlApplicationContext( "applicationContext.xml");
Robot robot = (Robot) cpac.getBean("robot");
robot.say();
}
Spring的FactoryBean接口实例化
类实现FactoryBean<T>接口,重写getObject()和getObjectType()方法
配置XML文件,bean的实例为getObject方法的返回值
具体实例如下所示:
//java代码
public class Factory implements FactoryBean<User> {@Override
br/>@Override
return new User(1,"李白","123");}
@Override
br/>}
@Override
return User.class;
}
}
//xml配置
<bean id="user" class="com.jungle.www.controller.Factory"/>
//注:在测试类中,使用getbean("user")即可得到User的实例
当bean已经配置成功后,如何测试呢?
首先得读取xml配置文件:
ApplicationContext context= new ClassPathXmlApplicationContext( "applicationContext.xml");
然后通过调用其方法,得到对象:
User user = context.getBean("user", User.class)
下面总结一下基本的API吧
核心API
BeanFactory IOC容器的基本接口
ApplicationContext 扩展的IOC容器接口
ClassPathXmlApplicationContext 基于xml配置文件的IOC容器
依赖注入
英文简称DI
英文全称: Dependency Inject
注入方式
setter注入
必须提供setter方法
构造器注入
注:name和index任选一项即可代表你的选择
bean的作用域
prototype
原型 => 每次创建一个实例
singleton
单例[默认] => 一个bean的定义,只有一个实例,不是一个类只有一个实例
request
一个请求一个实例
session
一个会话一个实例
websocket
一次websocket链接一个实例
bean的生命周期
初始化和销毁
在bean配置上写init-method和destroy-method
实现InitializingBean和DisposableBean及其方法
在容器关闭的时候销毁
//例:
public class Cycle2 implements InitializingBean, DisposableBean {@Override
br/>@Override
}
@Override
br/>System.out.println("开始....");
}
@Override
System.out.println("结束了....");
}
}
配置方式
ps:下面的代码实现,是在IDEA中使用Maven来进行构建和管理,不会Maven的可以去网站:https://how2j.cn/k/idea/idea-maven-config/1353.html学习学习
方式一[纯XML实现]
项目结构
APP类
public class App
{
public static void main( String[] args )
{
ClassPathXmlApplicationContext cpac =
new ClassPathXmlApplicationContext(
"applicationContext.xml");
MainUI mainUI = cpac.getBean("mainUI", MainUI.class);
mainUI.mainUI();
}
}
MianUI类
public class MainUI {
private UserService userService;
public void mainUI(){
Scanner temp = new Scanner(System.in);
while(true){
System.out.println("请输入登录账号:");
String account = temp.next();
System.out.println("请输入登录密码:");
String password = temp.next();
User user = userService.judgeUser(account, password);
if(null != user){
System.out.println("登录成功");
System.exit(0);
}else{
System.out.println("账号或密码错误,请重新登录");
}
}
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
在此类中,声明了UserService类的userService变量,区别于传统的赋值方式,这里仅仅只是声明了该变量,根据java的编程规范,未赋值的引用变量,默认值为null.
Spring要做的,就是将userService赋值,而采用xml配置方式,是需要setter方法的,所以在最后添加了一个setUserService方法
UserServiceImpl类
public class UserServiceImpl implements UserService {
private UserDAO userDAO;@Override
br/>@Override
return userDAO.select(account,password);
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
代码分析:有一个变量userDAO需要赋值
UserDAOImpl类
public class UserDAOImpl implements UserDAO {
private QueryRunner qr;@Override
br/>@Override
//建立一个解决数据库下划线问题的对象
BasicRowProcessor brp = new BasicRowProcessor(new GenerousBeanProcessor());
//准备sql语句,实际应用时不要用 来查询,影响效率
String sql = "select from user where user_account=? and user_password=?";
//准备填充数据
Object[] obj = {account,password};
//进行查询操作
User user = null;
try {
user = qr.query(sql, new BeanHandler<User>(User.class, brp),obj);
} catch (SQLException e) {
throw new RuntimeException("query异常",e);
}
return user;
}
public void setQr(QueryRunner qr) {
this.qr = qr;}
}
此代码中,有一个名叫qr的成员变量需要赋值,而这里还执行了数据库的查询操作,需要在pom.xml文件中引入jar包
User类
@Data
br/>}
}
此代码中,有一个名叫qr的成员变量需要赋值,而这里还执行了数据库的查询操作,需要在pom.xml文件中引入jar包
User类
@Data
br/>@NoArgsConstructor
private int UserId;
private String UserAccount;
private String UserPassword;
}
在这里,使用了lombok来给私有的成员变量建立getter、setter方法和空参构造及有参构造
applicationContext.xml文件配置
<!--在App类中开始启动,需要得到MainUI类的实例-->
<!--在MainUI类中,存在有叫userService的实例,
所以properties的name代表的就是实例名,ref指引用的地址-->
<bean id="mainUI" class="com.jungle.www.controller.MainUI">
<property name="userService" ref="userService"/>
</bean>
<!--得到UserServiceImpl的实例,UserServiceImpl的实例中存在有叫userDAO的实例-->
<bean id="userService" class="com.jungle.www.service.serviceimp.UserServiceImpl">
<property name="userDAO" ref="UserDAO"/>
</bean>
<!--UserDAOImpl的实例存在有qr的实例,所以得给qr赋值-->
<bean id="UserDAO" class="com.jungle.www.dao.daoimp.UserDAOImpl">
<property name="qr" ref="queryRunner"/>
</bean>
<!--通过构造器(
public QueryRunner(DataSource ds) {
super(ds);
})
得到QueryRunner的实例,需要传一个DataSouce的实例-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="druidDataSource"/>
</bean>
<!--德鲁伊连接池-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.classDriver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置文件-->
<bean id="propertySourcesPlaceholderConfigurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="druid.properties"/>
</bean>
druid.properties文件
jdbc.classDriver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/blog?userUnicode=true&characterEncoding=utf8
jdbc.user=root
jdbc.password=root123
pom.xml文件配置
<!--数据库_驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--数据库_工具包-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!--数据库_德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<!--SpringFrameWork-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
完整代码已上传:
链接:https://pan.baidu.com/s/1X64xcNhcqxOkr6sntraiBw
提取码:upuc
方式二[注解]
通过注解方式可以更加快速配置,只需要在类上面加上注解即可
注册springbean
@Controller 加在Controller层的实现类上
@Service 加在Service层的实现类上
@Repository 加在Dao层的实现类上@Component加类上,该类就会被Spring识别
br/>@Component加类上,该类就会被Spring识别
生命周期 @PostConstruct @PreDestroy
作用域范围 @Scope方式三[java配置]
注解:
@Bean
br/>方式三[java配置]
注解:
@Bean
br/>@Configuration
br/>@ComponentScan
加入@Controller…@Autowired
br/>再次简化
加入@Controller…@Autowired
AOP
Aspect Oritented Programming AOP 面向切面编程
Object Oritened Proguramming OOP 面对对象编程
概念
具有横切性质的系统功能,例如:日志记录、性能统计、事务管理、安全检查等等。散布在系统的各个类中。需要一种机制能将这类功能自动加入到需要的位置中去。这种机制就是AOP。
名词
连接点 joinpoint 需要加入功能的位置(方法)
切入点 pointcut 执行加入功能的连接点,从连接点选出的需要加入功能的连接点
通知 advice 需要实现的功能
切面 aspect 切入点和通知的组合
目标对象 target 连接点(方法)所在的对象
织入 weave 将切面应用到目标对象的过程
步骤
1) 编写service类
2) 编写通知 , 实现MethodBeforeAdvice接口
//method 要执行的方法
// args 方法的参数
// target 方法所在的对象
public void before(Method method, Object[] args, Object target) throws Throwable {
}
3)配置xml
配置service
配置通知
配置切入点,class= org.springframework.aop.support.JdkRegexpMethodPointcut ,配置属性pattern=> service的方法
配置切面,class=org.springframework.aop.support.DefaultPointcutAdvisor 连接切入点和通知
包装service类, class= org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
获取bean,调用方法,将会看到通知执行了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--目标对象-->
<bean id="userService" class="com.jungle.spring.aop.service.impl.UserServiceImpl"/>
<!--通知: 实现了打日志的功能-->
<bean id="beforeExecution" class="com.jungle.spring.aop.component.BeforeExecution"/>
<!--切入点:选出了需要增加功能的方法-->
<bean id="pointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value="com.jungle.spring.aop.service.impl.UserServiceImpl.addUser"/>
</bean>
<!--切面:连接切入点和通知,让打日志功能在切入点的位置执行-->
<bean id="aspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="pointCut"/>
<property name="advice" ref="beforeExecution"/>
</bean>
<!--包装userService-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
</beans>
通知类型
前置通知 : 方法执行之前 MethodBeforeAdvice
后置通知 : 方法执行之后 AfterReturningAdvice
环绕通知 : 方法执行前后 MethodInterceptor
异常通知 : 抛出异常时
最终通知 : finally执行时
注:面向接口编程 1)解耦,修改实现类 2)默认使用接口的方式生成代理
依赖
aspectj
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
通知类型
前置通知 : 方法执行之前 MethodBeforeAdvice
后置通知 : 方法执行之后 AfterReturningAdvice
环绕通知 : 方法执行前后 MethodInterceptor
异常通知 : 抛出异常时
最终通知 : finally执行时
注:面向接口编程 1)解耦,修改实现类 2)默认使用接口的方式生成代理
依赖
aspectj
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。