Spring bean容器中的bean有单例bean,也有多例bean。当我们需要给一个单例beanA注入一个单例beanB,或者给一个多例beanA注入一个多例或单例beanB时,都可以通过配置让Spring的bean容器帮我们完成。但如果我们需要给一个单例beanA注入一个多例beanB时,仅仅通过配置Spring是无法帮我们的单例beanA注入一个多例beanB的,即无法让我们每次使用beanB时都使用的是一个全新的beanB。因为beanA只初始化一次,相对应的Spring只会给beanA注入一个beanB。解决办法是给beanA注入一个ApplicationContext,这样我们就可以在每次需要使用beanB时都从ApplicationContext中获取一个新的beanB。
注入ApplicationContext有两种方式,实现ApplicationContextAware接口和通过@Autowired或@Resource注解标注让Spring进行自动注入。
实现ApplicationContextAware接口
ApplicationContextAware接口中定义一个setApplicationContext()方法,对于实现了该接口的bean,Spring将通过调度对应的setApplicationContext()方法将当前ApplicationContext传递过去。
public class Hello implements ApplicationContextAware { private ApplicationContext applicationContext; /** * Spring将通过该方法给我们的bean注入当前的ApplicationContext */ public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } }
通过注解标注
在使用注解进行配置时,我们也可以通过注解来告诉Spring要为当前的bean注入哪些内容。对于ApplicationContext也是一样的,可以通过对应的注解来告诉Spring将为我们注入对应的ApplicationContext。自动注入的注解可以是@Resource,也可以是@Autowired。
public class Hello { private ApplicationContext applicationContext; @Resource public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } }
Spring
有一种机制,可以动态的实现或重写bean
容器中指定bean
的指定方法,然后将返回值指定为bean
容器中的另一个bean
1、在beanA
对应的类中定义一个方法用来获取BeanB
,有这么一个方法就行,可以是空实现,到时候将由Spring
来为我们重写或实现,然后返回一个BeanB
类型的bean
。为此,可以将我们的BeanA
如下定义:
public class BeanA { /** * 需要使用到BeanB的方法 */ public void doSomething() { BeanB beanB = this.getBeanB(); System.out.println(beanB); //... } /** * 定义一个返回值为BeanB的方法,用来获取BeanB类型的bean,该方法将由Spring来重写。 * @return */ public BeanB getBeanB() { return null; } }
2、在ApplicationContext
中定义一个单例beanA
和一个多例beanB
,同时通过lookup-method
元素指定beanA
的getBeanB
方法将会被Spring
重写并返回bean
容器中的beanB
。
<bean id="beanB" class="com.app.BeanB" scope="prototype"/> <bean id="beanA" class="com.app.BeanA"> <!-- 表示将由Spring重写getBeanB()方法,并返回名为beanB的bean --> <lookup-method name="getBeanB" bean="beanB"/> </bean>
经过以上两步以后每次在调度beanA的getBeanB()方法时,Spring都重新从bean容器中获取一个beanB,因为beanB定义为多例形式,所以每次都会获取一个全新的BeanB对象。
在给一个bean指定了lookup-method后,Spring将通过CGLIB动态的生成一个该bean对应类型的子类,然后在该子类中实现或重写lookup-method元素指定的方法,并从bean容器中获取lookup-method元素指定的bean作为返回值进行返回。
当bean指定的类型是一个抽象类且lookup-method指定的方法是一个抽象方法时,Spring就将实现该抽象方法,否则就是重写。定义lookup-method的bean真正的类型是Spring动态生成类的类型,但是它可以被当做bean本身指定的类型使用,因为动态生成的类就是继承自bean本身指定的类型的。
由于Spring是需要动态生成类来重写或实现指定的方法的,所以我们必须确保由lookup-method指定的方法是可以被重写的,这就要求该方法对子类是可访问的,而且不能是final型的。具体来讲lookup-method元素指定的方法需要具有如下形式:
<public|protected> [abstract] <return-type> methodName(no-arguments)
如你所见,lookup-method
指定的方法还不能有参数。
参考:
https://blog.csdn.net/elim168/article/details/74915352