您的位置:首页 > 编程语言 > Java开发

【Spring源码--AOP的实现】(一)AopProxy代理对象的创建

2016-09-06 18:53 711 查看

前言:

本篇是以ProxyFactoryBean的配置来讲的,这个是最能体现AOP思想的一个配置方式。后续会写下<aop:config>配置的源码,那个就稍微复杂点,我们后续再讲。
我在网上搜了下,很多举例都是通过main方法加载配置文件实现ProxyFactoryBean的,这里我是用页面掉用action实现该配置。原理是一样的,不知道大家有没有这样一种感觉,就是要找到web类型的案例才觉得有用,因为我们用的web太多了。

设计原理:

我们先来看下以ProxyFactory为中心的相关类的继承图:【这个图好丑,凑合着看下】


这里我们分别简单介绍下这几个类:

ProxyConfig:可以看成一个数据基类,它可以为ProxyFactoryBean这样的子类提供配置属性。
AdvisedSupport:封装了AOP对通知和通知器的相关操作,这些操作对于不同的AOP代理对象的生成都是一样的,但具体AOP对象的生成都是由子类完成的。
ProxyCreatorSupport:看名字就可以猜到,它是一个辅助类,具体生成AOP对象依然是继续交给子类完成。
AspectJProxyFactory:集成Spring和AspectJ的作用,适用于需要使用AspectJ的AOP应用。
ProxyFactoryBean:Spring的AOP应用,可以在IOC中声明式配置。
ProxyFactory:Spring的AOP应用,需要编程式使用。

配置ProxyFactoryBean

1)、Advisor通知器,这个通知器实现了对目标对象的增强行为,也就是Advice通知。
2)、定义ProxyFactoryBean:interceptorNames是指定义的通知器,可以有多个;target,需要增强的类,从源码上看只能有一个。
<bean name="userService" class="com.gh.test.service.impl.UserServiceImpl"></bean>
<bean name="userDao" class="com.gh.test.dao.impl.UserDaoImpl"></bean>

<!--配置Advice-->
<bean name="logAdvice" class="com.gh.test.aop.LoggerAdvice"></bean>

<!--配置ProxyFactoryBean-->
<bean name="aopmethod" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>logAdvice</value>
</list>
</property>
<property name="target" ref="userService"></property>
</bean>
再来简单看下我们这个自定义的loggerAdvice:
public class LoggerAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("系统日志:"+(new Date())+":"+"调用了"+method.getName()+" :使用了参数"+(Arrays.toString(args)));
}
}
具体的调用时页面出发action,页面及struts代码我就不贴了,简单看下action:
public class UserAction {
public String addUser(){
UserService userService = ApplicationContextUtil.getBean("aopmethod");
BackUser user = new BackUser();
user.setUsername("哈哈");
user.setPassword("12345");
userService.addUser(user);
return "success";
}
}
这样一个简单的web配置,已经可以实现对增加user时的UserSevice进行增强,在调用前输出日志:
系统日志:Tue Sep 06 19:36:02 CST 2016:调用了addUser :使用了参数[User[addtime=null , username=哈哈 , password=12345]]
增加user

ProxyFactoryBean生成AopProxy代理对象

这里的ProxyFactoryBean是一个FactoryBean,对于FactoryBean这种Spring应用中经常出现的Bean的工作形式,前面的文章我已经讲过了FactoryBean的原理。从FactoryBean中获取对象,是通过getObject方法作为入口完成的,我们来看下这里的getObject方法。
代码1.1:ProxyFactoryBean的getObject方法
public Object getObject() throws BeansException {
//初始化通知器链
initializeAdvisorChain();
//如果目标对象是单态模式
if (isSingleton()) {
//调用获取单态模式对象的方法产生AOPProxy代理
return getSingletonInstance();
}
//如果目标对象是原型模式
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
//调用原型模式对象方法每次创建一个新的AOPProxy代理对象
return newPrototypeInstance();
}
}
这里面有三个方法,注释已经写的很清楚了,我们先来看initializeAdvisorChain方法,这里会有个标志位,如果已经初始化过,就不再初始化。来看下代码:
代码1.2:ProxyFactoryBean的initializeAdvisorChain方法
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
//如果通知器链已经被初始化,则直接返回,即通知器链只在第一次获取代理对象时产生
if (this.advisorChainInitialized) {
return;
}
//如果ProxyFactoryBean中配置的连接器列名名称不为空
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
//如果没有Bean工厂(容器)
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
//全局通知器不能是通知器链中最后一个,除非显式使用属性指定了目标
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
//遍历通知器链,向容器添加通知器
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
//如果通知器是全局的
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
//向容器中添加全局通知器
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
//如果通知器不是全局的
else {
Object advice;
//如果通知器是单态模式
if (this.singleton || this.beanFactory.isSingleton(name)) {
//从容器获取单态模式的通知或者通知器
advice = this.beanFactory.getBean(name);
}
//如果通知器是原型模式
else {
//创建一个新的通知或者通知器对象
advice = new PrototypePlaceholderAdvisor(name);
}
//添加通知器
addAdvisorOnChainCreation(advice, name);
}
}
}
//设置通知器链已初始化标识
this.advisorChainInitialized = true;
}
这里主要是对interceptorNames等元素的处理,我们继续看获取单例或多例的对象的具体代码:
代码1.3:ProxyFactoryBean的getSingletonInstance、newPrototypeInstance方法
// 获取一个单态模式的AOPProxy代理对象
private synchronized Object getSingletonInstance() {
// 如果单态模式的代理对象还未被创建
if (this.singletonInstance == null) {
// 获取代理的目标源
this.targetSource = freshTargetSource();
// 如果ProxyFactoryBean设置了自动探测接口属性,并且没有配置代理接且不是目标对象的直接代理类
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// 获取代理对象的目标类
Class targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
// 设置代理对象的接口
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass,this.proxyClassLoader));
}
// 初始化共享的单态模式对象
super.setFrozen(this.freezeProxy);
// 调用ProxyFactory生成代理AOPProxy对象
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}

// 获取一个原型模式的代理对象
private synchronized Object newPrototypeInstance() {
if (logger.isTraceEnabled()) {
logger.trace("Creating copy of prototype ProxyFactoryBean config: "
+ this);
}
// 根据当前的AOPProxyFactory获取一个创建代理的辅助类
ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
// 获取一个刷新的目标源
TargetSource targetSource = freshTargetSource();
// 从当前对象中拷贝AOP的配置,为了保持原型模式对象的独立性,每次创建代理对象时都需要拷贝AOP的配置,以保证原型模式AOPProxy代理对象的独立性
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// 设置代理接口
copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));
}
copy.setFrozen(this.freezeProxy);
if (logger.isTraceEnabled()) {
logger.trace("Using ProxyCreatorSupport copy: " + copy);
}
// 调用ProxyFactory生成AOPProxy代理
return getProxy(copy.createAopProxy());
}
单例多例的不同模式代码大家应该可以理解,我们重点看这么一个方法,getProxy(AopProxy)方法,我们来观察下这个方法


重点观察下,这里的参数是AopProxy,也就是说我们的createAopProxy方法已经生成了代理对象,那么我们就要看下这个代理对象时怎么生成的。
代码1.4:DefaultAopProxyFactory的createAopProxy方法
// 创建AOPProxy代理的入口方法
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 调用DefaultAopProxyFactory的创建AOPProxy代理的方法
return getAopProxyFactory().createAopProxy(this);
}

// 创建AOP代理对象
public AopProxy createAopProxy(AdvisedSupport config)
throws AopConfigException {
// 如果AOP使用显式优化,或者配置了目标类,或者只使用Spring支持的代理接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
// 获取AOP配置的目标类
Class targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException(
"TargetSource cannot determine target class: "
+ "Either an interface or a target is required for proxy creation.");
}
// 如果配置的AOP目标类是接口,则使用JDK动态代理机制来生成AOP代理
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
// 如果AOP配置的目标类不是接口,则使用CGLIB的方式来生成AOP代理
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. "
+ "Add CGLIB to the class path or specify proxy interfaces.");
}
return CglibProxyFactory.createCglibProxy(config);
} else {
return new JdkDynamicAopProxy(config);
}
}
那么这里是根据了AOP目标类是否为接口来判断生成代理对象的方式,那么我们刚才配置的就是走jdk的动态代理模式。那么从上面的代码看到这个时候我们已经得到了一个AopProxy类,这个类并不是我们要的代理对象。那么具体它又是怎么取得代理对象,我们要从getProxy(AopProxy aopProxy)方法中去看。

JDK生成AopProxy对象

我们直接从getProxy方法进去就可以看到该方法。
代码1.5:JdkDynamicAopProxy类的getProxy方法
// 创建AOP代理对象
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is "
+ this.advised.getTargetSource());
}
// 获取AOPBeanFactory中配置的代理接口
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
// 查找代理目标的接口中是否定义equals()和hashCode()方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 使用JDK的动态代理机制创建AOP代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
具体内容也是比较简单,先取得代理对象的代理接口配置,然后调用Proxy的newProxyInstance方法。这里创建代理对象的时候,需要指明3个参数,一个是类加载器、一个是代理接口、另一个是Proxy回调方法所在的对象,这个对象需要实现InvocationHandler接口。这里JdkDynamicAopProxy本身就实现了该接口,所以可以使用this对象本身作为参数。

CGLIB生成AopProxy对象

这个代码相对多一点,主要内容呢就是对Enhancer对象进行各种配置,然后通过Enhancer对象去生成代理对象。来看代码
代码1.6:Cglib2AopProxy类的getProxy方法
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB2 proxy: target source is "
+ this.advised.getTargetSource());
}
try {
// 从代理创建辅助类中获取在IoC容器中配置的目标对象
Class rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null,"Target class must be available for creating a CGLIB proxy");
// 将目标对象本身做为自己的基类
Class proxySuperClass = rootClass;
// 检查获取到的目标类是否是CGLIB产生的
if (AopUtils.isCglibProxyClass(rootClass)) {
// 如果目标类是有CGLIB产生的,获取目标类的基类
proxySuperClass = rootClass.getSuperclass();
// 获取目标类的接口
Class[] additionalInterfaces = rootClass.getInterfaces();
// 将目标类的接口添加到容器AOP代理创建辅助类的配置中
for (Class additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 校验代理基类
validateClassIfNecessary(proxySuperClass);
// 配置CGLIB的Enhancer类,Enhancer是CGLIB中的主要操作类
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader&& ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// 设置enhancer的基类
enhancer.setSuperclass(proxySuperClass);
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
// 设置enhancer的接口
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setInterceptDuringConstruction(false);
// 设置enhancer的回调方法
Callback[] callbacks = getCallbacks(rootClass);
enhancer.setCallbacks(callbacks);
// 将通知器中配置作为enhancer的方法过滤
enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap,
this.fixedInterceptorOffset));
Class[] types = new Class[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// 设置enhancer的回调类型
enhancer.setCallbackTypes(types);
// 创建代理对象
Object proxy;
if (this.constructorArgs != null) {
proxy = enhancer.create(this.constructorArgTypes,this.constructorArgs);
} else {
proxy = enhancer.create();
}
return proxy;
} catch (CodeGenerationException ex) {
throw new AopConfigException(
"Could not generate CGLIB subclass of class ["
+ this.advised.getTargetClass()
+ "]: "
+ "Common causes of this problem include using a final class or a non-visible class",
ex);
} catch (IllegalArgumentException ex) {
throw new AopConfigException(
"Could not generate CGLIB subclass of class ["
+ this.advised.getTargetClass()
+ "]: "
+ "Common causes of this problem include using a final class or a non-visible class",
ex);
} catch (Exception ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}


那么到这里,通过使用AopProxy对象封装target目标对象之后,ProxyFactoryBean的getObject方法得到的对象就不是一个普通的Java对象了,而是一个AopProxy的代理对象。这个时候已经不会让应用直接调用target的方法实现了,而是先被AopProxy代理对象拦截,对于不同的Aopproxy代理对象的不同生成方法,拦截入口不同。比如:JDK使用的是InvocationHandler使用的是invoke入口,二Cglib使用的是设置好的callback回调。

如果把AOP的实现部分看成是由 基础设施准备和AOP运行辅助两个部分组成,那么这个第一部分是我们刚刚所探讨的内容。通过这个准备过程,把代理对象、拦截器(通知器)这些待调用的部分都准备好,等待着AOP运行过程中对这些基础设施的使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: