1. Spring Aop 配置式Aop Demo
上篇中通过手动写代码, 将 Pointcut, MethodInterceptor, ProxyFactory, TargetBean 组装起来, 最终通过 ProxyFactory.getProxy() 来获取代理的对象; 而本篇将结合 Spring 中的 FactoryBean 结合起来, 只需要在 xml 中配置少许 信息就能对目标对象生成代理对象, 配置的信息如下:
<!-- Simple target -->
<bean id="kk" class="com.lami.foodie.aop.aop1.KK"></bean>
<!-- MethodInterceptor -->
<bean id="simpleMethodInterceptor" class="com.lami.foodie.aop.aop1.SimpleMethodInterceptor"/>
<!-- ProxyFactoryBean -->
<bean id="test1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces"><value>com.lami.foodie.aop.aop1.KK</value></property>
<property name="target"><ref bean="kk" /></property>
<property name="interceptorNames"><value>simpleMethodInterceptor</value></property>
</bean>
PS: 上面配置文件对应的类在上篇中已存在
2. Spring Aop 配置式Aop 组件 ProxyFactoryBean
ProxyFactoryBean 是通过 FactoryBean 来针对指定的 targetBean 来创建动态代理对象 (PS: FactoryBean 是 Spring IOC 中针对创建指定对象的抽象工厂, 毕竟有些类的创建过程是很复杂的, 所以出现了 FactoryBean 这个角色), 其主要有一下属性:
/**
* This suffix in a value in an interceptor list indicates to expand globals.
*/
public static final String GLOBAL_SUFFIX = "*";
protected final Log logger = LogFactory.getLog(getClass());
// 从字面意思上, 下面是拦截器, 其实不然, 下面支持获取指定前缀的 advice/MethodInterceptor, 当然也可以在下面的数组的最后一位设置 target 的名字 (PS: 这在checkInterceptorNames中解析)
private String[] interceptorNames;
// 代理的目标类 target, 这个 String 主要是通过xml 设置, 或通过 checkInterceptorNames 方法上
private String targetName;
// 自动获取 target 上的 interface
private boolean autodetectInterfaces = true;
// PS: 这里的 singleton 指的是 advice 是否是 singleton
private boolean singleton = true;
// 前置 Spring aop 中主要使用的是 MethodInterceptor, 而在 xml 中配置的 <aop> 标签中解析出来的都是 advice, 这时需要对应的适配器 -> 将 advice 适配成 MethodInterceptor
// 这里的 advisorAdapterRegistry 中主要是将 advice, MethodInterceptor 包装成 Advisor, 与将 Advisor 转成 MethodInterceptor
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
// 设置是否 动态代理的配置信息是否变化
private boolean freezeProxy = false;
// 创建动态代理时使用的 classLoader
private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();
// 配置是否已经配置了 classLoader
private transient boolean classLoaderConfigured = false;
// 创建动态时使用的 BeanFactory
private transient BeanFactory beanFactory;
// 标示动态代理中的 advisorChain 链是否已经创建好
/** Whether the advisor chain has already been initialized */
private boolean advisorChainInitialized = false;
// 这个类其实就是动态代理创建的最终对象
/** If this is a singleton, the cached singleton proxy instance */
private Object singletonInstance;
以上这些属性中最重要的还是 interceptorNames(拦截器链), targetName(代理的类), 将 advice/advisor 转换成 MethodInterceptor 的适配器注册工厂 advisorAdapterRegistry, 有了以上的属性, 则再通过下面的的两个方法就能创建代理对象:
public Object getObject() throws BeansException {
// 这里初始化通知器链
initializeAdvisorChain();
// 这里对 Singleton prototype 的类型进行区分, 生成对应的 Proxy
if (isSingleton()) {
return getSingletonInstance();
}
else { // prototype 模式则每次创建一个类
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
// 动态代理对象 singletonInstance
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource(); // 返回对应的 target
// 自动获取需要动态代理的接口
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
// 这里设置代理对象的接口
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); // 获取 targetClass 的所有的 interface
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
// 注意这里的方法将会使用 ProxyFactory 来生成
// 通过 createAopProxy 返回 合适的 AopProxy(JdkDynamicAopProxy, CglibAopProxy), 并将 AopProxy 传如 getProxy 方法中进行动态代理
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
3. Spring Aop 配置式Aop ProxyFactoryBean 创建对象流程
整个创建代理对象的整个过程是在 ProxyFactoryBean 的 getObject 方法中触发的, 大体流程如下:
1. 初始化 AdvisorChain
1.1 循环遍历 interceptorNames, 从 BeanFactory 中获取对应 Advice, MethodInterceptor, 通过 AdvisorAdaptorRegistry 包装成 Advisor 加入到 AdvisorChain 里面
2. 调用 getSingletonInstance方法, 创建动态代理对象
2.1 根据 targetName 从 BeanFactory 中拿到对应对象
2.2 获取 target 类实现的所有接口 <- 为代理这些接口准备数据
2.3 DefaultAopProxyFactory 根据 AdvisedSupport 来创建合适的 AopProxy (JdkDynamicAopProxy, CglibAopProxy) , 判断的条件主要是 optimize, targetClass, hasNoUserSuppliedProxyInterfaces
2.4 Aop 根据已经获取到的 Advisor, Target 等信息创建代理对象
(PS: 其实理解了上篇的编程式 Aop, 则这里的 ProxyFactoryBean 就很好理解了; 另外插一下 aop 很重要, Spring 里面的很多特性都是基于 aop, 比如 事务, 缓存, Hystrix 等)
4. 总结:
本篇讲述通过 ProxyFactoryBean 来创建代理对象, 整个创建过程其实和上篇差不多, 也就是说 ProxyFactoryBean 只是做了 MethodInterceptor 的自动获取, 以及 通过 ProxyFactory 创建代理对象, 而问题也在 ProxyFactoryBean 中, 从这个类中我们发现, 只要需要创建一个动态代理对象, 则就需要配置一个 ProxyFactoryBean <-- 而在一般项目中需要创建很多动态代理对象, 可想而知这是多么可怕的事情, 所以就出现了 AbstractAutoProxyCreator(自动获取 BeanFactory 中的所有 Advice/MethodInterceptor, 并针对所有符合 Pointcut 的对象创建代理对象, 这也是下篇将叙述的内容)。
5. 参考:
Spring Aop核心源码分析
Spring技术内幕
Spring 揭秘
Spring 源码深度分析
开涛 Spring 杂谈
伤神 Spring 源码分析
Spring源码情操陶冶
网友评论