在软件开发中,有些行为对于很多地方都是通用的;例如我们需要记录用户所有的操作日志,使用面向对象编程(OOP)的话,需要在每个方法里面去引用这种公共的行为,这样程序中就会产生大量的重复代码。
对于日志、安全、事物等分布于应用中多处而又相同的功能,是需要与应用的业务逻辑相分离的,所以就有了面向切面编程(AOP);在AOP中,关注的方向是横向的,不同于OOP的纵向,所以这些分布于应用中多处的功能被称为横切关注点。
用一段代码示例来进行解释说明:
@Aspect
public class AopDemo {
@Pointcut("execution(* *.test(..))")
public void test() {
}
@Before("test()")
public void beforeTest() {
System.out.println("beforeTest");
}
@After("test()")
public void afterTest() {
System.out.println("afterTest");
}
@Around("test()")
public Object aroundTest(ProceedingJoinPoint point) {
System.out.println("before1");
Object object = null;
try {
object = point.proceed();
} catch (Throwable t) {
t.printStackTrace();
}
System.out.println("after1");
return object;
}
}
在Spring中,需要使用AspectJ的切点表达式语言来定义切点。
AspectJ指示器 | 描述 |
---|---|
execution | 用于匹配是连接点的执行方法 |
arg() | 限制连接点匹配参数为 指定类型的执行方法 |
@arg() | 限制连接点匹配参数为 由指定注解标注的执行方法 |
this() | 限制连接点匹配AOP代理的Bean引用为 指定类型的类 |
target() | 限制连接点匹配目标对象为指定类型的类 |
@target() | 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解 |
within() | 限制连接点匹配 指定的类型 |
@within() | 限制连接点匹配 指定注解所标注的类型(使用Spring AOP时,方法定义在由指定的注解所标注的类中)(对象级别) |
@annotation | 限制匹配带有指定注解的连接点(方法级别) |
示例3:(bean()指示器的使用)
execution(* com.springinaction.springidol.Instrument.play()) and bean(eddie)
execution(* com.springinaction.springidol.Instrument.play()) and !bean(eddie)
public class TestBean {
public void test() {
System.out.println("---------test---------");
}
}
@Aspect
public class AopDemo {
@Pointcut("execution(* *.test(..))")
public void test() {
}
@Before("test()")
public void beforeTest() {
System.out.println("beforeTest");
}
@After("test()")
public void afterTest() {
System.out.println("afterTest");
}
@Around("test()")
public Object aroundTest(ProceedingJoinPoint point) {
System.out.println("before1");
Object object = null;
try {
object = point.proceed();
} catch (Throwable t) {
t.printStackTrace();
}
System.out.println("after1");
return object;
}
}
spring-aspectj-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy/>
<bean id="test" class="org.bgy.spring.study.spring.aop.simple.demo.TestBean"/>
<bean id="aopDemo" class="org.bgy.spring.study.spring.aop.simple.demo.AopDemo"/>
beans>
public class AopTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-aspectj-context.xml");
TestBean testBean = applicationContext.getBean("test", TestBean.class);
testBean.test();
}
}
// Output:
before1
beforeTest
---------test---------
after1
afterTest
可以看到,除了打印的 ---------test--------- 之外,在它打印的前后,还对我们的增强操作进行了打印;这样就实现了对所有类的test()方法进行了增强,使切面功能可以独立于核心逻辑之外,方便程序的扩展和解耦。上面写到了开启Spring AOP的方法是使用配置
,这是一个自定义注解;我们在Spring——3. 自定义标签的解析中讲过,如果声明了自定义注解,就一定会在程序中注册对应的处理器和解析器。
我们使用 aspectj-autoproxy 进行全局搜索,搜到了在 AopNamespaceHandler类中存在这样一段代码:
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// In 2.0 XSD as well as in 2.5+ XSDs
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace in 2.5+
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
所以,AopNamespaceHandler类是这个自定义注解的处理器,里面 aspectj-autoproxy对应的 AspectJAutoProxyBeanDefinitionParser类是自定义注解的解析器。
按照以前讲的自定义注解的解析的内容我们可以知道,在解析配置文件的时候,一旦遇到
所有的解析器都是对 BeanDefinitionParser接口的统一实现,所以入口都是从parse()方法开始的,AspectJAutoProxyBeanDefinitionParser的parse():
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 注册 AnnotationAwareAspectJAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 注解中子类的处理
extendBeanDefinition(element, parserContext);
return null;
}
其中的关键逻辑在于 registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法:
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册或升级 AutoProxyCreator定义beanName为
// org.springframework.aop.config.internalAutoProxyCreator 的BeanDefinition
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 对于proxy-target-class以及 expose-proxy属性的处理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册组件并通知,便于监听器做进一步的处理;
// 其中BeanDefinition的 className为 AnnotationAwareAspectJAutoProxyCreator
registerComponentIfNecessary(beanDefinition, parserContext);
}
这个方法中主要完成了3件事情:
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 注册或者升级 AnnotationAwareAspectJAutoProxyCreator
// 实现了自动注册 AnnotationAwareAspectJAutoProxyCreator 类的功能
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 如果存在了自动代理创建器;
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 且自动代理创建器和现在的不同
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
// 就需要根据优先级来判断到底需要使用哪个
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
// 改变bean最重要的就是改变bean所对应的className属性
apcDefinition.setBeanClassName(cls.getName());
}
}
// 如果跟现在相同,直接返回
return null;
}
// 如果不存在,或者存在了不同的创建器,都需要重新进行注册 BeanDefinition;
// 使用 AnnotationAwareAspectJAutoProxyCreator 来创建一个 BeanDefinition,并注册到 internalAutoProxyCreator 中
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
// 对于 proxy-target-class属性的处理(proxy-target-class属性:用于指定CGLIB的代理)
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 对于 expose-proxy属性的处理(expose-proxy属性:解决目标对象内部的自我调用无法实现切面的增强)
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
public interface AService {
public void a();
public void b();
}
@Service
public class AServiceImpl1 implements AService {
@Transactional(propagation = Propagation.REQUIRED)
public void a(){
this.b();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void b(){
}
}
此处的this执行目标对象,所以调用this.b()将不会执行b事务切面,即不会执行事务的增强;为了解决这个问题,我们需要设置:
上面讲到了通过自定义配置来完成了对 AnnotationAwareAspectJAutoProxyCreator的bean的自动注册,下面就来看看这个类到底是怎么实现了AOP的。
先来看看AnnotationAwareAspectJAutoProxyCreator 类的层次结构:
可以看到,AnnotationAwareAspectJAutoProxyCreator 类实现了InstantiationAwareBeanPostProcessor接口,来看看InstantiationAwareBeanPostProcessor接口的源码:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
InstantiationAwareBeanPostProcessor接口又实现了 BeanPostProcessor接口:
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
所以对于 InstantiationAwareBeanPostProcessor 来说除了具有父接口以外的两个方法还自己定义了四个方法,这6个方法的作用分别是:
方法 | 描述 |
---|---|
postProcessBeforeInstantiation | 最先执行的方法;在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走 |
postProcessAfterInstantiation | 在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返回true,postProcessPropertyValues就会被执行 |
postProcessProperties | 调用时机为postProcessAfterInstantiation执行之后并返回true, 返回的PropertyValues将作用于给定bean属性赋值 |
postProcessPropertyValues | 已经被标注@Deprecated,将会被postProcessProperties取代 |
postProcessBeforeInitialization | BeanPostProcessor接口中的方法;在Bean的自定义初始化方法之前执行 |
postProcessAfterInitialization | BeanPostProcessor接口中的方法;在Bean的自定义初始化方法执行完成之后执行 |
回到代码,再来看看AnnotationAwareAspectJAutoProxyCreator的父类 AbstractAutoProxyCreator中的代码,可以看到这个类中主要重写了 postProcessBeforeInstantiation() 和 postProcessAfterInitialization()方法,所以我们对于AOP的分析,应该由这两个方法入手。
根据上面写到的执行顺序,应该先执行postProcessBeforeInstantiation()方法,再执行postProcessAfterInitialization()方法。
AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// shouldSkip:在这里就会首先去加载一次增强器
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
AspectJAwareAdvisorAutoProxyCreator.java
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
// 获取增强器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
可以看到,在执行shouldSkip()方法的时候,就会首先去加载一次切面中的所有增强器,然后判断是否需要跳过。
接着上面看,由于我们分析的是使用注解完成的AOP,所以对于 findCandidateAdvisors()方法的实现是由 AnnotationAwareAspectJAutoProxyCreator类完成的,跟下去:
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持;所以这里保留了父类方法: 先加载配置文件中定义的增强
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 并添加了:获取注解定义的增强
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
我们这里使用的是注解,所以应该是由 this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来完成对于增强器的获取:
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 获取所有的beanName(包括系统自己注入的bean)
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
// 获取bean对应的类型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 判断这个bean是否被@Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 增强器的获取(获取标记AspectJ注解中的增强方法)
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 把获取到的增强器加入缓存中
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 从缓存中获取
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
这一段看起来很多的代码,其实思路非常清晰,总结下来就是实现了以下几个功能:
在上面实现的功能中,最重要也最复杂的就是对于bean进行增强器的提取,并把这一功能委托给了 getAdvisors()方法进行实现:
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
再看上面一行代码:
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
这行代码中创建了一个MetadataAwareAspectInstanceFactory类型的factory对象:
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
AspectMetadata getAspectMetadata();
@Nullable
Object getAspectCreationMutex();
}
通过这个factory我们可以获取到AspectMetadata对象:
public class AspectMetadata implements Serializable {
private final String aspectName;
private final Class<?> aspectClass;
private transient AjType<?> ajType;
private final Pointcut perClausePointcut;
.......
}
所以是这个对象中封装了被@Aspect注解标注的bean的 name,class,ajType等…
回到getAdvisors()方法:
ReflectiveAspectJAdvisorFactory.java
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取标记为 AspectJ 的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 获取增强方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 获取增强器,包含了 切点,切面方法名称,增强的类名...等等
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
// 判断如果配置了增强 延迟初始化
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
// 就需要在首位加入 同步实例化增强器
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 获取 DeclaredParents 注解(DeclaredParents 主要用于 引介增强的注解形式 的实现,实现方式与普通增强很类似
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
增强器的获取逻辑通过 getAdvisor()方法实现,包括了对切点信息的获取和根据切点信息生成增强器:
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 切点信息的获取(即指定注解的表达式信息的获取,如 @Around("test()") )
AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 根据切点信息生成增强器,所有的增强器都由 Advisor 的实现类 InstantiationModelAwarePointcutAdvisorImpl 进行封装
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
切点信息的获取,即指定注解的表达式信息的获取,如 @Around(“test()”):
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 获取方法上的注解(示例:@org.aspectj.lang.annotation.Around(argNames=, value=test()) )
AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 使用 AspectJExpressionPointcut 实例封装获取的信息
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 提取注解中的表达式(示例:@Around("test()") 中的 test() 、@Pointcut("execution(* *.test(..))") 中的 execution(* *.test(..)))
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
// 根据这些注解类型去跟方法进行匹配来获取(只获取这些方法的注解)
// (Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class)
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
// 获取指定方法上的注解,并使用 AspectJAnnotation封装;method要和toLookFor匹配
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
return new AspectJAnnotation<>(result);
}
else {
return null;
}
}
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {Pointcut.class, Around.class, Before.class,
After.class, AfterReturning.class, AfterThrowing.class};
首先是获取方法上声明的注解,注解的获取是根据常量 ASPECTJ_ANNOTATION_CLASSES 定义的类型来匹配获取的(即只能获取Pointcut、Around…等注解)。
然后使用 AspectJExpressionPointcut类型的ajexp对象 封装了切点信息,再把获取到的注解中定义的表达式设置到 ajexp对象的 expression属性中。
根据切点信息生成增强;所有的增强器都由 Advisor的实现类 InstantiationModelAwarePointcutAdvisorImpl统一封装:
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
InstantiationModelAwarePointcutAdvisorImpl.java
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 示例:
// test()
this.declaredPointcut = declaredPointcut;
// class org.bgy.spring.study.spring.aop.simple.demo.AspectJDemo
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
// beforeTest
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
// public void org.bgy.spring.study.spring.aop.simple.demo.AspectJDemo.beforeTest()
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
// 1 (Around: 0; Before: 1; After: 2)
this.declarationOrder = declarationOrder;
// aspectName
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 根据注解中的信息初始化对应的增强器(@Before、@After标签的不同,会使增强器增强的位置不同)
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
这个封装(也就是实例化对象)的过程,就是把切点的信息简单的赋值给新对象的各个属性;在简单属性赋值完成之后,还需要完成对于增强器的初始化。
因为不同类型的增强器实现的逻辑是不一样的,例如 @Before(“test()”)和@After(“test()”)两种增强器增强的位置就不相同,所以需要不同的增强器实现类来完成不同的逻辑; 这个不同增强器实现类的初始化过程,就是在instantiateAdvice()方法中完成的。
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
ReflectiveAspectJAdvisorFactory.java
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 获取标注了 @Aspect 注解的类
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 获取 candidateAdviceMethod 方法上面标注的 切面注解
AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 根据不同的注解类型,封装不同的增强器;再实例化
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
在这里,会首先去获取方法上面标注的Aspect相关的注解,然后根据注解的不同类型来生成不同的增强器;例如 AtAround会对应生成 AspectJAroundAdvice、AtBefore会对应生成 AspectJMethodBeforeAdvice…等。
这里各种不同类型的增强器里面具体的执行方法(也就是invoke()方法),我们等到后面在讲代理对象调用时的方法调用顺序的时候一起来讲。
下面接着看剩下的两个步骤。
如果获取到的增强器不为空,并且配置了增强延迟初始化,那么就需要在首位加入同步实例化增强器:
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
// 就需要在首位加入 同步实例化增强器
advisors.add(0, instantiationAdvisor);
}
protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {
public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {
super(aif.getAspectMetadata().getPerClausePointcut(), (MethodBeforeAdvice)
// 目标方法前调用,类似@Before
// 简单初始化aspect
(method, args, target) -> aif.getAspectInstance());
}
}
DeclaredParents 主要用于引介增强的注解形式的实现,它的实现方式也与普通增强很类似,只是使用了 DeclareParentsAdvisor 对功能进行封装:
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
// 最后再添加到 advisors中
advisors.add(advisor);
}
}
private Advisor getDeclareParentsAdvisor(Field introductionField) {
DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
if (declareParents == null) {
// Not an introduction field
return null;
}
if (DeclareParents.class == declareParents.defaultImpl()) {
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
}
// 使用 DeclareParentsAdvisor 进行封装
return new DeclareParentsAdvisor(
introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}
到这里,已经完成了对于标注了@Aspect的bean中的所有增强器的获取。
return super.shouldSkip(beanClass, beanName);
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}
static boolean isOriginalInstance(String beanName, Class<?> beanClass) {
if (!StringUtils.hasLength(beanName) || beanName.length() !=
beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {
return false;
}
return (beanName.startsWith(beanClass.getName()) &&
beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));
}
AbstractAutoProxyCreator.java
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果需要被代理,则需要封装指定的bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果已经被处理过了,不处理
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果不需要增强,不处理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// bean是否是基础设施类,基础设施类不应被代理;配置了需要跳过的bean也不需要代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 获取增强器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果获取到了,即需要代理,则针对增强器创建代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
这里也会先去获取一下增强器,如果获取到了,才会创建代理;所以我们总结一下,创建代理主要包含了两个步骤:
AbstractAutoProxyCreator.java
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
AbstractAdvisorAutoProxyCreator.java
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有的增强
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 获取所有增强中适用于当前bean的增强
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
可以看到,这里对于增强器的获取分成了两个步骤:
获取所有的增强器:
List<Advisor> candidateAdvisors = findCandidateAdvisors();
可以看到这里对于增强器的获取还是使用的 findCandidateAdvisors()方法,所以从上面2.2.2.1.1 加载所有增强器小节的分析来看,我们已经获取过了所有的增强器,所以这里的获取就直接从缓存中进行获取了:
// 从缓存中获取
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory =
this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
寻找匹配的增强器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
在获取完所有的增强器之后,还存在一个问题:对于所有的增强器来讲,并不一定都适用于当前的bean,也就是需要满足上面1.2.1 定义切点小节中讲到的一些表达式中限制连接点匹配的指定类型,指定bean等条件。
所以还需要挑选出能够满足我们配置的通配符的bean:
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 过滤出满足当前bean的增强器
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
AopUtils.java
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
// 如果传入的Advisor集合为空的话,直接返回这个空集合
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
// 首先处理引介增强(引介增强:可以为目标类通过AOP的方式添加一些接口实现)
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
// 如果是引介增强,上面已经处理了,跳过
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 对于普通bean的处理
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
// 如果是IntroductionAdvisor的话,则调用IntroductionAdvisor类型的实例进行类的过滤
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
// 通常我们的Advisor都是PointcutAdvisor类型
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
// 从Advisor中获取Pointcut的实现类 这里是AspectJExpressionPointcut
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// 进行切点表达式的匹配最重要的就是 ClassFilter 和 MethodMatcher这两个方法的实现
// 先进行ClassFilter的matches方法校验
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 再进行 MethodMatcher 方法级别的校验
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
// 只要有一个方法能匹配到就返回true;这里就会有一个问题:
// 因为在一个目标中可能会有多个方法存在,有的方法是满足这个切点的匹配规则的,但是也可能有一些方法是不匹配切点规则的
// 所以在运行时进行方法拦截的时候还会有一次运行时的方法切点规则匹配
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
然后这里的 pc.getClassFilter().matches(targetClass) 是要从 AspectJExpressPointcut中获取ClassFilter;再然后就是到AspectJExpressPointcut中去进行定义的表达式中去进行匹配和过滤了,这个过程aspectj的内容了,很复杂,我觉得就没必要去深究了…
到这里,获取到了所有标注了@Aspect的bean中所有的增强器,并且筛选出了匹配当前bean的增强器,增强器的获取到此结束。
我们先来总结一下增强器的获取步骤:
在获取了所有对应bean的增强器后,就可以进行代理的创建了。
为了避免文章篇幅过长,就把创建代理放到下一篇文章Spring——6. AOP介绍及源码实现(二)中继续分析。