一、Method Injection
1、通常通过将一个bean定义为另一个bean的属性来处理依赖关系。当bean的生命周期不同时,假设单例beanB需要使用非单例(原型)beanA,可能是在B的方法调用上。会出现问题,BeanA和BeanB都变成单例作用域。
例子:
创建一个bean对象BeanA(对象的作用域为多例)
package com.it.app.MethodI;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class BeanA {
}
创建一个bean对象BeanB(对象为单例,且依赖BeanA)
package com.it.app.MethodI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("singleton")
public class BeanB {
@Autowired
private BeanA beanA;
public void getBeanHash() {
System.out.println("beanB的hash值: " + this.hashCode());
System.out.println("beanA的hash值: " + beanA.hashCode());
}
}
配置一个扫描BeanA、BeanB对象的类,@ComponentScan注解扫描两个对象所在包下放到容器中。
package com.it.app.config;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan("com")
public class AppConfig {
}
打印BeanA、BeanB对象的hash值,并且打印对象hash值,启动容器:
package com.it.app;
import com.it.app.MethodI.BeanB;
import com.it.app.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppFour {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
BeanB beanB = (BeanB) context.getBean("beanB");
beanB.getBeanHash();
beanB.getBeanHash();
}
}
测试结果:
beanB的hash值: 583015088
beanB的hash值: 1091781053
beanB的hash值: 583015088
beanB的hash值: 1091781053
测试结果发现单例对象BeanB一直是同一个值是单例,而BeanA作为多例对象注入到BeanA中时,也变成单例对象。hash值相同。
2、解决方法
(1)通过ApplicationContextAware接口
修改对象BeanB对象:
package com.it.app.MethodI;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("singleton")
public class BeanB implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void getBeanHash() {
System.out.println("beanB的hash值: " + this.hashCode());
System.out.println("beanA的hash值: " +this.applicationContext.getBean("beanA", BeanA.class).hashCode());
}
}
测试结果:BeanA作用域为多例(官网说提示:该操作是不可取的,因为业务代码知道Spring框架并与之耦合)。
beanB的hash值: 502891368
beanA的hash值: 566891420
beanB的hash值: 502891368
beanA的hash值: 577734751
(2) Lookup Method Injection (通过@Lookup注解)
修改BeanB对象
package com.it.app.MethodI;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("singleton")
public abstract class BeanB {
@Lookup
public abstract BeanA createBeanA();
public void getBeanHash() {
System.out.println("beanB的hash值: " + this.hashCode());
System.out.println("beanA的hash值: " +createBeanA().hashCode());
}
}
输出结果值:
beanB的hash值: 49547843
beanA的hash值: 1417554340
beanB的hash值: 49547843
beanA的hash值: 478182173