代码示例
测试类如下:
输出结果如下:
这里发现了一个问题,我们定义了 ScopeProxyBean 是 prototype 模式的,但是现在 hashCode() 却是同一个,是因为在使用 @Autowired 注入的时候就已经把值确定了,只调用了一次 getBean() 操作,所以不管你是否配置了 bean 的 Scope 是 singleton 还是 prototype 模式,最终拿到的都是同一个对象。
如果想要解决这个问题,让 @Autowired 注入就是要 prototype 的。可以使用代理。可以在 @Scope 中按照如下配置:
但是今天这里不使用这种方式,而是采用提前代理的方式(自定义 TargetSource 方式) 解决这个问题。
提前生成代理对象
可以从 resolveBeforeInstantiation() 方法中做文章。此时注意这里还是在 doCreateBean() 真正创建对象之前,就已经在做拦截操作了,这里要是有值返回就直接不会去真正实例化 bean 了。
进入 AbstractAutoProxyCreator 代码如下:这里有一样非常关键的方法,getCustomTargetSource() 方法获取自定义的目标对象,如果这个方法有返回值,就表示你已经自定义了目标对象(所以这就是你可以下手的地方),Spring 会去为这个自定义目标对象创建代理对象,但是条件是设么呢?那就要追踪 getCustomTargetSource() 方法了,看这个方法满足什么条件才会有返回值?
进入到 getCustomTargetSource() 方法,如下:只有当 customTargetSourceCreators 变量不为 null,该方法才会有返回值,那就着重看这个 customTargetSourceCreators 变量的值是怎么来的
发现该后置处理器暴露了一个接口 setCustomTargetSourceCreators() 可以设置变量 customTargetSourceCreators 的值
如果要往 AbstractAutoProxyCreator 后置处理器中设置值,注意这是一个内置的后置处理器,所以你必须在这个后置起之前先注册到容器中,可以实现权重接口,就和上次社会 InterceptorNames 一个道理,源码如下:
然后此时 AbstractAutoProxyCreator 类中 customTargetSourceCreators 变量就有值了, customTargetSourceCreator 就是我们自定义的 creator,继承了一个 AbstractBeanFactoryBasedTargetSourceCreator 类,源码如下:
然后自定义的 TargetSource 如下所示: 直接继承 AbstractBeanFactoryBasedTargetSource 类,getTarget() 方法实现逻辑和 @Scope 中的 SimpleBeanTargetSource 类一样,就是去调用 getBean() 创建 bean,但是注意这个 BeanFactory 是深拷贝出来的新的 BeanFactory,里面踢除了 @Aspect 切面的入口类。
然后再回到 getCustomTargetSource() 方法,继续向下执行
执行到 getTargetSource() 方法,进入方法内部,源码如下:
只有 createBeanFactoryBasedTargetSource() 方法返回值才会往下执行代码,上面我们已经自定义好了 targetSource,直接继承这个AbstractBeanFactoryBasedTargetSource 类,代码如下:
然后再回到调用处 getTargetSource() 方法,此时 targetSource != null,代码往下执行,这里调用了一个 getInternalBeanFactoryForBean() 方法主要是拷贝 BeanFactory和踢除切面功能,然后重新给这个 beanName new 了一个 BeanDefinition ,并且还是 prototype 多例,并且 BeanFactory 是新拷贝出来的了。
进入 getInternalBeanFactoryForBean() 方法内部,主要是拷贝了一个 BeanFactory,然后新的 BeanFactory 把切面生成代理类入口给踢除了,这样在使用新的 BeanFactory 调用 getBean() 方法就不会受 @Aspect 切面的影响,源码如下:
回到上一层调用处处,源码如下:此时 targetSource 已经有值了,并且是我们返回的自定义的 targetSource
自己定义的 targetSource 对象,源码如下:
再回到 getCustomTargetSource() 方法调用处,源码如下:此时我们把我们自己返回的 targetSource 传进去了,注意 targetSource 里面的 getTarget() 方法才会真正返回一个 bean 实例,会去调用 getBean() 操作。
进入到 createProxy() 源码如下:我们穿进去的 targetSource 保存到了 ProxyFactory 对象的 targetSource 变量中了,然后就是去创建这个 bean 的代理实例了。
因为这是个代理对象,当他调用方法的时候,必然会触发 invoke() 方法,所以看到 invoke() 逻辑里面,源码如下:
此时的 TargetSource 是我们自定义的,所以会调用我们自己的 getTarget() 方法,源码如下:此时注意这里的 BeanFactory 是从原来的 BeanFactory 中拷贝出来的,并且还把切面功能踢除了,这里就不会再发生代理对象的生成了。
然后调用 getBean() 方法,直接实例化 ScopeProxyBean,至此我们提前在创建 bean 实例之前完成了 bean 创建。
通过这种方式创建的 bean,在真正去调用的时候才会触发去调用 getBean() 流程创建真实的实例,并且 BeanFactory 是深拷贝出来的,会把 @Aspect 切面踢除了的,就算你配置了 @Aspect 功能也无效。
还要注意一点就通过这种方式提前创建的 bean 默认都是 prototype 多例的,Spring 内部将其修改成 prototype 多例模式,具体原因还未知…
至此,上面的测试代码,for 循环 10 次最终会打印出 10 个不同的 hashCode 值,如下所示:
会自定义 TargetSource 了,那么去分析 @Scope 注解下面的配置就很清晰了。
只是入口不一样而已,自定义 TargetSource 是从 resolveBeforeInstantiation() 方法开始。
而 @Scope 的支持是从 invokeAwareMethods() 方法开始的
详细对 @Scope 的源码解析在另一篇文章中…
最后配上源码方便复制粘贴
配置类和实体类
/**
* 演示 ScopeProxy
*/
@Configuration
@ComponentScan(basePackages = {"com.gwm.spring.proxy"})
@EnableAspectJAutoProxy
public class ScopedMainConfig {
}
@Component
@Scope("prototype")
//@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ScopeProxyBean {
public void code() {
System.out.println(this.hashCode());
}
}
自定义 TargetSource
public class MyCustomTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {
public MyCustomTargetSourceCreator() {
System.out.println("MyCustomTargetSourceCreator....构造方法");
}
@Override
protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(Class<?> beanClass, String beanName) {
System.out.println("MyCustomTargetSourceCreator---------->beanName="+beanName);
if (getBeanFactory() instanceof ConfigurableListableBeanFactory) {
BeanDefinition beanDefinition = ((ConfigurableListableBeanFactory) getBeanFactory()).getBeanDefinition(beanName);
if (!beanClass.isAssignableFrom(ScopeProxyBean.class)) {
return new MyCustomTargetSource();
}
}
return null;
}
}
public class MyCustomTargetSource extends AbstractBeanFactoryBasedTargetSource implements Serializable {
private static final long serialVersionUID = 1949093163787033304L;
@Override
public Object getTarget() throws Exception {
System.out.println("MyCustomTargetSource...被调用了....");
return getBeanFactory().getBean(this.getTargetBeanName());
}
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor, PriorityOrdered,BeanFactoryAware {
private BeanFactory factory;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof AbstractAutoProxyCreator) {
System.out.println("postProcessAfterInitialization---------->beanName="+beanName);
AbstractAutoProxyCreator creator = (AbstractAutoProxyCreator) bean;
//AnnotationAwareAspectJAutoProxyCreator creator = (AnnotationAwareAspectJAutoProxyCreator) bean;
// 注册 MyTargetSourceCreator
MyCustomTargetSourceCreator customTargetSourceCreator = new MyCustomTargetSourceCreator();
customTargetSourceCreator.setBeanFactory(factory);
creator.setCustomTargetSourceCreators(customTargetSourceCreator);
}
/** 这里记得返回 */
return bean;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.factory = beanFactory;
}
@Override
public int getOrder() {
return 45;
}
}
测试代码
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ScopedMainConfig.class);
ScopeProxyBeanDemo bean = context.getBean(ScopeProxyBeanDemo.class);
for (int i = 0; i < 10; i++) {
bean.test();
}
}