控制反转 IoC

Spring 的依赖注入

构造函数注入

  1. public class MyBean {
  2. private OtherBean bean;
  3. private String name;
  4. // 构造函数注入
  5. public MyBean(OtherBean otherBean, String name) {
  6. this.bean = otherBean;
  7. this.name = name;
  8. }
  9. }
  1. <!-- 其他注入的bean -->
  2. <bean id="otherBean" class="com.alberto.service.impl.OtherBean" />
  3. <!-- 通过构造器注入的bean,id是注入的bean名称,ref是通过名称找到的bean -->
  4. <bean id="myBean" class="com.alberto.service.impl.MyBean">
  5. <!-- 不止index,也可以用name属性,类似于下面setter注入的name,不同之处是name为构造器的参数变量名,类似的还有根据type -->
  6. <constructor-arg index="0" type="com.alberto.service.impl.OtherBean" ref="otherBean"/>
  7. <constructor-arg index="1" type="java.lang.String" value="default_string_value"/>
  8. </bean>

setter 注入

  1. public class MyBean {
  2. private OtherBean bean;
  3. private String name;
  4. // setter注入
  5. public void setBean(OtherBean otherBean) {
  6. this.bean = otherBean;
  7. }
  8. // setter注入
  9. public void setName(String name) {
  10. this.name = name;
  11. }
  12. }
  1. <!-- 其他注入的bean -->
  2. <bean id="otherBean" class="com.alberto.service.impl.OtherBean" />
  3. <!-- 通过setter注入的bean -->
  4. <bean id="myBean" class="com.alberto.service.impl.MyBean">
  5. <!-- property的name不是字段名,而是setXxx方法中的Xxx -->
  6. <property name="bean" type="com.alberto.service.impl.OtherBean" ref="otherBean"/>
  7. <property name="name" type="java.lang.String" value="default_string_value"/>
  8. </bean>

工厂注入

静态工厂注入

  1. // 使用静态工厂注入一个OtherBean,再将该otherBean通过setter注入到MyBean
  2. public class MyStaticFactory {
  3. public static OtherBean getOtherBean() {
  4. return new OtherBean();
  5. }
  6. }
  7. public class MyBean {
  8. private OtherBean bean;
  9. private String name;
  10. // setter注入
  11. public void setBean(OtherBean otherBean) {
  12. this.bean = otherBean;
  13. }
  14. // setter注入
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. }
  1. <!-- 调用factory的方法获取bean -->
  2. <bean id="otherBean" class="com.alberto.factory.MyStaticFactory" factory-method="getOtherBean" />
  3. <bean id="myBean" class="com.alberto.service.impl.MyBean">
  4. <property name="bean" type="com.alberto.service.impl.OtherBean" ref="otherBean"/>
  5. <property name="name" type="java.lang.String" value="default_string_value"/>
  6. </bean>

实例工厂注入

  1. // 使用实例工厂注入所需要的全部bean,再将这些bean注入到MyBean
  2. public class MyInstanceFactory {
  3. public OtherBean getOtherBean() {
  4. return new OtherBean();
  5. }
  6. public String getName() {
  7. return "default_string_value";
  8. }
  9. }
  10. public class MyBean {
  11. private OtherBean bean;
  12. private String name;
  13. // setter注入
  14. public void setBean(OtherBean otherBean) {
  15. this.bean = otherBean;
  16. }
  17. // setter注入
  18. public void setName(String name) {
  19. this.name = name;
  20. }
  21. }
  1. <!-- 调用factory的方法注册两个bean -->
  2. <bean id="factory" class="com.alberto.factory.MyInstanceFactory" />
  3. <bean id="otherBean" factory-bean="factory" factory-method="getOtherBean" />
  4. <bean id="name" factory-bean="factory" factory-method="getName" />
  5. <!-- 将注册好的bean再注册到myBean中 -->
  6. <bean id="myBean" class="com.alberto.service.impl.MyBean">
  7. <property name="otherBean" ref="otherBean"/>
  8. <property name="name" ref="name"/>
  9. </bean>

@Autowired@Resource

@Autowired @Resource
来源 Spring J2EE
作用范围 字段、setter、构造器 字段、setter
默认装配方式 按类型 按名称
改变装配方式 默认优先顺序:类型 -> 名称;
结合 @Qualifier 按名称装配
默认优先顺序:名称 -> 类型
可选属性 required:允许 Bean 为 null name:指定 Bean 的名称
type:指定 Bean 的类型
单接口多实现问题的解决
- Bean 名称与具体实现相同,根据名称装配;
- 使用 @Qualifier 注解声明名称;
- 在类上添加 @Primary 注解声明默认装配的类。

- @Resource 注解声明 name 字段,实现类的 @Service 注解声明 beanName。
通用解决方式
- 将name、type存入 Map 中进行区分;
- 通过 Spring 的 ApplicationContext 获取(applicationContext.getBean("<Bean名称>"))。

面向切面编程 AOP

动态代理机制

Spring 的 AOP 是基于动态代理实现的,将目标类的实例与调用方

JDK 动态代理

是 Spring AOP 的默认动态代理方式。
针对使用了接口的方式,在使用时调用接口类中提供的方法,执行的则是委托类的具体实现。
JDK 动态代理的实现机制是通过反射机制动态生成代码,在运行期间动态产生代理类的字节码并加载到 JVM(调用具体实现的委托类,提供给调用方)。
代码实现见此。

CGLib 动态代理

CGLib 是一个开源库,针对没有接口的情况进行动态代理,作为 JDK 动态代理的补偿。
CGLib 动态代理的实现机制是通过字节码技术为委托类生成一个代理类(该代理类实际上就是委托类的一个子类,因此不能对被 final 修饰的类进行代理)。
代码实现见此。

Bean 管理相关

Bean 创建时机

默认的 Bean 都是以单例的形式存在,默认创建的 Bean 都是在主启动类启动时加载并创建;可以使用 @Lazy 注解实现懒加载加快 IoC 的加载进度。

懒加载:被其他 Bean 引用或显式地从 BeanFactory 获取时才会加载该 Bean。

Bean 注入时机

主启动类启动时,IoC 容器将 Bean 实例化并通过默认为 setter 的注入方式,在构造函数执行后进行注入。