Spring IOC注入
手动注入
set方法注入
需要提供set方法
public class UserService {private UserDao userDao;
public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}
设置属性字段的值
<bean id="userService" class="com.shsxt.service.UserService"><!-- 通过property标签设置字段的值name:属性字段的名称 (setXXX)ref:指定的bean标签的id--><property name="userDao" ref="userDao" />
</bean>
<bean id="userDao" class="com.shsxt.dao.UserDao">
</bean>
构造器注入
通过构造器的参数注入
public class UserService {private UserDao userDao;
// 带参构造public UserService(UserDao userDao) {this.userDao = userDao;}
}
设置属性字段的值
<bean id="userService" class="com.shsxt.service.UserService"><!-- 通过constructor-arg标签设置字段的值name:属性字段的名称ref:指定的bean标签的id--><constructor-arg name="" ref=""/>
</bean>
<bean id="userDao" class="com.shsxt.dao.UserDao">
</bean>
循环依赖问题
当两个或多个类需要互相注入时,构造器注入会出现循环依赖问题。可以通过set方法注入解决。
自动注入
环境准备
-
在xml配置文件中引入context的命名空间及规范
-
开启自动注入
<context:annoation-config />
-
在需要注入的属性字段上添加注解 (属性字段是JavaBean)
@Resource
-
默认根据id属性值查找 (属性字段名与id属性值保持一致)
-
如果id属性值不一致,则会根据(Class)类型查找
-
注解可以声明在属性字段级别 或 set方法级别
-
属性字段可以提供set方法,也可以不提供
-
注解可以通过name属性设置别名,如果设置了name属性,就必须要求name属性与bean标签的id属性值一致
-
当一个对象有一个接口实现时,正常使用;如果有多个接口实现时,需要使用name设置别名
@Autowired
-
默认根据(Class)类型查找,与id属性值无关
-
注解可以声明在属性字段级别 或 set方法级别
-
属性字段可以提供set方法,也可以不提供
-
可以结合@Qualifier设置别名,需要设置@Qualifier的name属性值,name属性值与bean标签的id属性值一致
Spring IOC 扫描器
作用:
统一管理Bean,简化配置文件,提高开发效率
环境准备:
在配置文件中开启扫描器,并设置扫描范围
<context:componet-scan base-package="需要扫描的包目录"/>
注解:
声明在类级别
Controller层@Controller Service层@Service Dao层@Repository 任意类@Componet
Spring IOC Bean作用域与生命周期
Bean作用域
Spring IOC容器实例化的Bean'对象时单例对象!
单例作用域
当IOC容器实例化Bean对象时,会将实例化的Bean对象设置单例缓存池中,下次再从缓存池中获取
lazy-init懒加载
如果设置true,表示懒加载,IOC容器加载时,不进行Bean对象的实例化,而是在使用Bean对象时进行实例化
如果设置false,表示不懒加载,IOC容器加载时就实例化Bean对象,默认值
lazy-init懒加载为什么要设置为false?
1. 可以提前发现一些潜在的配置文件 2. IOC容器加载时会将Bean对象实例化,使用时不需在实例化,可以提高开发效率
什么对象适合作为单例?
无状态 或状态不可改变的对象
什么是无状态 或状态不可改变的对象?
不存在改变当前对象状态的成员变量。例:controller层、Service层、dao层
原型作用域
当IOC容器实例化Bean对象时,每次都会创建一个新的Bean对象
Web容器中的作用域
request作用域
session作用域
Bean的生命周期
Bean的定义
Bean的初始化
Bean的使用
Bean的销毁
IOC/DI
IOC/DI:控制反转/依赖注入
控制反转:将对象的创建过程转交给外部容器(IOC容器)来实现
依赖注入:给属性字段赋值 (JavaBean对象)
Spring AOP
代理模式
为一个委托类(目标对象)提供一个代理类(代理对象)
作用:可以通过代理对象实现目标对象的行为,并对目标对象的行为进行增强
两个原则:
1. 目标对象与代理对象有共同的行为 2. 代理对象增强目标对象
三要素:
1. 共同的行为 2. 目标对象 3. 代理对象
常见代理模式:
静态代理
动态代理
静态代理
1. 目标对象固定 2. 在程序运行前已经得到目标对象 3. 对目标对象进行增强 4. 当需要大量代理类是,可能会产生"类爆炸"
动态代理
在程序运行时,通过反射机制动态生成代理对象
JDK动态代理
注:要求目标对象有接口实现
通过Proxy类的newProxyInstance()得到代理对象
Object proxy = Proxy.newProxyInstance(类加载器, 接口数组, InvocationHandler接口);
InvocationHandler接口中有invoke方法,代理过程在invoke方法中执行
当代理对象调用方法时,即会执行invoke方法
CGLIB动态代理
注:采用继承思想,定义代理类继承目标类。目标类不能使用final修饰。
需要在pom.xml引入cglib的依赖。
通过Enhancer的create方法,可以生成一个类,并设置该类的父类为目标类。
通过设置Enhancer对象的Callback方法,在callback方法中实现代理过程。
利用MethodInterceptor接口,该接口是Callback的子接口。
Enhancer enhancer = new Enhancer();
// 设置目标类为父类
enhancer.setSuperClass(target.getClass());
// 设置代理过程
enhancer.setCallBack(MethodInterceptor接口);
// 生成类
Object proxy = enhancer.create();
MethodInterceptor接口接口中,一个intercept方法,代理过程在intercept方法中执行
当代理对象调用方法时,即会执行intercept方法