接着上一节:Spring aop(1)开篇的测试类分析:
public class TestAop {
public static void main(String[] args) {
//手工创建一个实例(Target)
ProxyService aspectJService = new ProxyServiceImpl();
//使用AspectJ语法 自动创建代理对象
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(aspectJService);
//添加切面和通知类
aspectJProxyFactory.addAspect(AopAdviceConfig.class);
//创建代理对象
ProxyService proxyService = aspectJProxyFactory.getProxy();
//进行方法调用
proxyService.testProxy();
}
}
从测试的代码可以看出,这段代码的重点是AspectJProxyFactory,首先我们来看下AspectJProxyFactory的UML类图:

我们来看看继承体系中涉及到类的作用:
a、Advisor:组合了Advice。
b、Advised:组合了Advisor和TargetSource即目标对象
c、AdvisedSupport:Advised的一个实现类。继承了ProxyConfig实现了Advised。
d、ProxyConfig:在Advised中定义了一系列的配置接口,像:是否暴露对象、是否强制使用CGlib等。ProxyConfig是对这些接口的实现,但是ProxyConfig却不是Advised的实现类
e、ProxyCreatorSupport:AdvisedSupport的子类。引用了AopProxyFactory用来创建代理对象。
f、AspectJProxyFactory:ProxyCreatorSupport的子类。用来创建代理对象。使用AspectJ语法。(ProxyFactory、ProxyFactoryBean、AspectJProxyFactory这三个类功能都是一样的,但是使用场景各不相同。)
测试类解析:
1、我们先来看看new AspectJProxyFactory(aspectJService)构造方法代码如下:
public AspectJProxyFactory(Object target) {
//检测目标对象不能为null
Assert.notNull(target, "Target object must not be null");
//设置目标对象的所有的接口
this.setInterfaces(ClassUtils.getAllInterfaces(target));
//设置目标对象
this.setTarget(target);
}
2、接着我们来看看aspectJProxyFactory.addAspect(AopAdviceConfig.class):
public void addAspect(Class<?> aspectClass) {
//全限定类名
String aspectName = aspectClass.getName();
//根据切面对象创建切面元数据类
AspectMetadata am = this.createAspectMetadata(aspectClass, aspectName);
//根据传入的切面类创建元数据 切面class实例 将切面实例封装为切面实例工厂
MetadataAwareAspectInstanceFactory instanceFactory = this.createAspectInstanceFactory(am, aspectClass, aspectName);
//从切面实例工厂中获取Advisor。
this.addAdvisorsFromAspectInstanceFactory(instanceFactory);
}
上面的代码分别执行了:this.createAspectMetadata、this.createAspectInstanceFactory、this.addAdvisorsFromAspectInstanceFactory这三个方法,我们分别来看下:
2.1: this.createAspectMetadata
a、我们来先看看那元数据的存储基本信息:
/**
* AspectMetadata 切面元数据类
*/
public class AspectMetadata implements Serializable {
/**
* 切面的名字 可能是类的全限定类名 也可能是Spring容器中bean的名字
*/
private final String aspectName;
/**
* 切面类 指带有切面注解的类
*/
private final Class<?> aspectClass;
/**
* 类的类型 这个是AspectJ中定义的类 存储了aspectClass类的类相关信息
* 实现类为 AjTypeImpl
*/
private transient AjType<?> ajType;
/**
* Spring AOP 中的切点表达式
*/
private final Pointcut perClausePointcut;
}
AspectMetadata这个类中主要存储了切面类的名字、切面类对象和AspectJ中定义的存储切面类Class对象的类以及SpringAOP中的切点表达式。
b、createAspectMetadata方法:
private AspectMetadata createAspectMetadata(Class<?> aspectClass, String aspectName) {
//直接调用 AspectMetadata的构造函数
AspectMetadata am = new AspectMetadata(aspectClass, aspectName);
//这里判断我们传入的切面类是不是切面很简单,即判断切面类上是否存在@Aspect注解。
if (!am.getAjType().isAspect()) {
throw new IllegalArgumentException("Class [" + aspectClass.getName() + "] is not a valid aspect type");
}
return am;
}
c、接着看看AspectMetadata的构造方法:
public AspectMetadata(Class<?> aspectClass, String aspectName) {
//传入的切面类名直接赋值
this.aspectName = aspectName;
Class<?> currClass = aspectClass;
AjType ajType;
//这里循环查找 带有Aspect的类,一直找到父类为Object
for(ajType = null; currClass != Object.class; currClass = currClass.getSuperclass()) {
AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass);
if (ajTypeToCheck.isAspect()) {
//这里的AjType所持有的aspectClass为带有@Aspect注解的类。
ajType = ajTypeToCheck;
break;
}
}
if (ajType == null) {
throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");
} else if (ajType.getDeclarePrecedence().length > 0) {
throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP");
} else {
this.aspectClass = ajType.getJavaClass();
this.ajType = ajType;
switch(this.ajType.getPerClause().getKind()) {
//perClausePointcut切点表达式初始化
//正常我们的Aspect类 都是SINGLETON 其他类型还不知道是什么
case SINGLETON:
this.perClausePointcut = Pointcut.TRUE;
return;
case PERTARGET:
case PERTHIS:
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setLocation(aspectClass.getName());
ajexp.setExpression(this.findPerClause(aspectClass));
ajexp.setPointcutDeclarationScope(aspectClass);
this.perClausePointcut = ajexp;
return;
case PERTYPEWITHIN:
this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(this.findPerClause(aspectClass)));
return;
default:
throw new AopConfigException("PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
}
}
}
2.2: this.createAspectInstanceFactory
a、我们在看createAspectInstanceFactory这个方法的代码:
private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(AspectMetadata am, Class<?> aspectClass, String aspectName) {
Object instanceFactory;
//我们在使用 @Aspect注解的时候都是直接在类上添加@Aspect注解所以以下条件会成立
if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//根据传入的切面类创建 切面对象 是一个单例 要求有无参构造函数
Object instance = this.getSingletonAspectInstance(aspectClass);
instanceFactory = new SingletonMetadataAwareAspectInstanceFactory(instance, aspectName);
} else {
//创建一个 SimpleMetadataAwareAspectInstanceFactory
instanceFactory = new SimpleMetadataAwareAspectInstanceFactory(aspectClass, aspectName);
}
return (MetadataAwareAspectInstanceFactory)instanceFactory;
}
今天先到这里。。。。
网友评论