【小家Spring】Spring AOP原理使用的基础类打点(AopInfrastructureBean、ProxyProcessorSupport、Advised、AjType)

article/2025/10/29 18:22:47

每篇一句

没被洪水灌溉过,你怎么能证明这个城市的下水道架构师合理的呢?

相关阅读

【小家Spring】探索Spring AOP中aopalliance的Joinpoint、MethodInvocation、Interceptor、MethodInterceptor…
【小家Spring】Spring AOP原理使用的基础类打点(AopInfrastructureBean、Advised、AjType、AspectJExpressionPointcut)
【小家Spring】详解Spring AOP的底层代理JdkDynamicAopProxy和ObjenesisCglibAopProxy的源码分析(介绍CGLIB使用中的坑)

前言

Spring AOP是整个Spring框架中最重要的内容之一。为了更好的深入查看它的原理,这篇文章主要是把它在关键位置使用到的一些常用类进行打点、解释一波,有助于我们去看源代码的时候变得更加的轻松、流畅

Spring AOP相关类、组件内容庞大。此处只会介绍一些最为常用的概念进行分析~~~

Spring AOP常用类解释

在这里插入图片描述

AopInfrastructureBean:免被AOP代理的标记接口

AopInfrastructureBean是一个标记接口。若Bean实现了此接口,表明它是一个Spring AOP的基础类,那么这个类是不会被AOP给代理的,即使它能被切面切进去~~~

ProxyConfig:AOP配置类

用于创建代理的配置的父类,以确保所有代理创建者具有一致的属性。 它有五个属性,解释如下:

public class ProxyConfig implements Serializable {// 标记是否直接对目标类进行代理,而不是通过接口产生代理private boolean proxyTargetClass = false;// 标记是否对代理进行优化。true:那么在生成代理对象之后,如果对代理配置进行了修改,已经创建的代理对象也不会获取修改之后的代理配置。// 如果exposeProxy设置为true,即使optimize为true也会被忽略。private boolean optimize = false;// 标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型//Advised接口其实就代表了被代理的对象(此接口是Spring AOP提供,它提供了方法可以对代理进行操作,比如移除一个切面之类的),它持有了代理对象的一些属性,通过它可以对生成的代理对象的一些属性进行人为干预// 默认情况,我们可以这么完 Advised target = (Advised) context.getBean("opaqueTest"); 从而就可以对该代理持有的一些属性进行干预勒   若此值为true,就不能这么玩了boolean opaque = false;//标记代理对象是否应该被aop框架通过AopContext以ThreadLocal的形式暴露出去。//当一个代理对象需要调用它【自己】的另外一个代理方法时,这个属性将非常有用。默认是是false,以避免不必要的拦截。boolean exposeProxy = false;//标记是否需要冻结代理对象,即在代理对象生成之后,是否允许对其进行修改,默认为false.// 当我们不希望调用方修改转换成Advised对象之后的代理对象时,就可以设置为true 给冻结上即可private boolean frozen = false;
}

ProxyProcessorSupport

简单的说它就是提供为代理创建器提供了一些公共方法实现:

public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean {/*** This should run after all other processors, so that it can just add* an advisor to existing proxies rather than double-proxy.* 【AOP的自动代理创建器必须在所有的别的processors之后执行,以确保它可以代理到所有的小伙伴们,即使需要双重代理得那种】*/private int order = Ordered.LOWEST_PRECEDENCE;// 当然此处还是提供了方法,你可以自己set或者使用@Order来人为的改变这个顺序~~~public void setOrder(int order) {this.order = order;}@Overridepublic int getOrder() {return this.order;}...// 这是它提供的一个最为核心的方法:这里决定了如果目标类没有实现接口直接就是Cglib代理// 检查给定beanClass上的接口们,并交给proxyFactory处理protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {// 找到该类实现的所有接口们~~~Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());// 标记:是否有存在【合理的】接口~~~boolean hasReasonableProxyInterface = false;for (Class<?> ifc : targetInterfaces) {if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&// 该接口必须还有方法才行,不要忘记了这步判断咯~~~~ifc.getMethods().length > 0) {hasReasonableProxyInterface = true;break;}}if (hasReasonableProxyInterface) {// Must allow for introductions; can't just set interfaces to the target's interfaces only.// 这里Spring的Doc特别强调了:不能值只把合理的接口设置进去,而是都得加入进去for (Class<?> ifc : targetInterfaces) {proxyFactory.addInterface(ifc);}}else {// 这个很明显设置true,表示使用CGLIB得方式去创建代理了~~~~proxyFactory.setProxyTargetClass(true);}}// 判断此接口类型是否属于:容器去回调的类型,这里例举处理一些接口 初始化、销毁、自动刷新、自动关闭、Aware感知等等protected boolean isConfigurationCallbackInterface(Class<?> ifc) {return (InitializingBean.class == ifc || DisposableBean.class == ifc || Closeable.class == ifc ||AutoCloseable.class == ifc || ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));}// 是否是如下通用的接口。若实现的是这些接口也会排除,不认为它是实现了接口的类protected boolean isInternalLanguageInterface(Class<?> ifc) {return (ifc.getName().equals("groovy.lang.GroovyObject") ||ifc.getName().endsWith(".cglib.proxy.Factory") ||ifc.getName().endsWith(".bytebuddy.MockAccess"));}
}

ProxyCreatorSupport

这个类应该很熟了,我们之前介绍过的三大创建代理对象的工厂ProxyFactoryBean、ProxyFactory、AspectJProxyFactory都是继承自此类的
参考:【小家Spring】面向切面编程Spring AOP创建代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory(JDK Proxy和CGLIB)

ProxyCreatorSupport用于设置和保存下面三大信息:

  1. 设置被代理对象target
  2. 设置代理接口
  3. 设置通知advice

ProxyCreatorSupport继承AdvisedSupport,主要提供了createAopProxy方法用来得到用来生成代理对象的AopProxy对象:

public class ProxyCreatorSupport extends AdvisedSupport {// new了一个aopProxyFactory public ProxyCreatorSupport() {this.aopProxyFactory = new DefaultAopProxyFactory();}protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}// 由此可议看出,它还是委托给了`AopProxyFactory`去做这件事~~~  它的实现类为:DefaultAopProxyFactoryreturn getAopProxyFactory().createAopProxy(this);}
}//DefaultAopProxyFactory#createAopProxy
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {// 对代理进行优化  或者  直接采用CGLIB动态代理  或者 //config.isOptimize()与config.isProxyTargetClass()默认返回都是false// 需要优化  强制cglib  没有实现接口等都会进入这里面来if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {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.");}// 倘若目标Class本身就是个接口,或者它已经是个JDK得代理类(Proxy的子类。所有的JDK代理类都是此类的子类),那还是用JDK的动态代理吧if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}// 实用CGLIB代理方式 ObjenesisCglibAopProxy是CglibAopProxy的子类。Spring4.0之后提供的// return new ObjenesisCglibAopProxy(config);}// 否则(一般都是有实现接口) 都会采用JDK得动态代理else {return new JdkDynamicAopProxy(config);}}// 如果它没有实现过接口(ifcs.length == )  或者 仅仅实现了一个接口,但是呢这个接口却是SpringProxy类型的   那就返回false// 总体来说,就是看看这个cofnig有没有实现过靠谱的、可以用的接口// SpringProxy:一个标记接口。Spring AOP产生的所有的代理类 都是它的子类~~private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {Class<?>[] ifcs = config.getProxiedInterfaces();return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));}
}

Objenesis是专门用于实例化一些特殊java对象的一个工具,如私有构造方法。我们知道带参数的构造等不能通过class.newInstance()实例化的,通过它可以轻松完成
基于Objenesis的CglibAopProxy扩展,用于创建代理实例,没有调用类的构造器(厉害了)

Advised

Advice: 通知拦截器
Advisor: 通知 + 切入点的适配器
Advised: 包含所有的Advised 和 Advice

该接口用于保存一个代理的相关配置。比如保存了这个代理相关的拦截器、通知、增强器等等。
所有的代理对象都实现了该接口(我们就能够通过一个代理对象获取这个代理对象怎么被代理出来的相关信息)

不管是JDKproxy,还是cglib proxy,代理出来的对象都实现了org.springframework.aop.framework.Advised接口;

在这里插入图片描述

public interface Advised extends TargetClassAware {boolean isFrozen();boolean isProxyTargetClass();//返回呗代理了的接口们Class<?>[] getProxiedInterfaces();// 检查这个指定的接口是否被代理了。。。boolean isInterfaceProxied(Class<?> intf);// 设置一个源。只有isFrozen为false才能调用此方法void setTargetSource(TargetSource targetSource);TargetSource getTargetSource();void setExposeProxy(boolean exposeProxy);boolean isExposeProxy();// 默认是false,和ClassFilter接口有关,暂时不做讨论void setPreFiltered(boolean preFiltered);boolean isPreFiltered();// 拿到作用在当前代理商得所有通知(和切面的适配器)Advisor[] getAdvisors();//相当于在通知(拦截器)链的最后一个加入一个新的void addAdvisor(Advisor advisor) throws AopConfigException;void addAdvisor(int pos, Advisor advisor) throws AopConfigException;boolean removeAdvisor(Advisor advisor);// 按照角标移除一个通知void removeAdvisor(int index) throws AopConfigException;int indexOf(Advisor advisor);boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;// 增加通知得相关方法  采用了适配器的模式// 最终都会变成一个DefaultIntroductionAdvisor(包装Advice的)void addAdvice(Advice advice) throws AopConfigException;void addAdvice(int pos, Advice advice) throws AopConfigException;boolean removeAdvice(Advice advice);int indexOf(Advice advice);String toProxyConfigString();}

下面看看基础实现AdvisedSupport

AdvisedSupport

它最重要的一个方法是:提供getInterceptorsAndDynamicInterceptionAdvice方法用来获取对应代理方法对应有效的拦截器链

AdvisedSupport本身不会提供创建代理的任何方法,专注于生成拦截器链。委托给ProxyCreatorSupport去创建代理对象

public class AdvisedSupport extends ProxyConfig implements Advised {@Overridepublic void addAdvisor(Advisor advisor) {int pos = this.advisors.size();addAdvisor(pos, advisor);}@Overridepublic void addAdvisor(int pos, Advisor advisor) throws AopConfigException {if (advisor instanceof IntroductionAdvisor) {validateIntroductionAdvisor((IntroductionAdvisor) advisor);}addAdvisorInternal(pos, advisor);}	// advice最终都会备转换成一个`Advisor`(DefaultPointcutAdvisor  表示切面+通知),它使用的切面为Pointcut.TRUE// Pointcut.TRUE:表示啥都返回true,也就是说这个增强通知将作用于所有的方法上/所有的方法// 若要自己指定切面(比如切点表达式),使用它的另一个构造函数:public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice)@Overridepublic void addAdvice(Advice advice) throws AopConfigException {int pos = this.advisors.size();addAdvice(pos, advice);}@Overridepublic void addAdvice(int pos, Advice advice) throws AopConfigException {Assert.notNull(advice, "Advice must not be null");if (advice instanceof IntroductionInfo) {// We don't need an IntroductionAdvisor for this kind of introduction:// It's fully self-describing.addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));}else if (advice instanceof DynamicIntroductionAdvice) {// We need an IntroductionAdvisor for this kind of introduction.throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");}else {addAdvisor(pos, new DefaultPointcutAdvisor(advice));}}// 这里需要注意的是:setTarget最终的效果其实也是转换成了TargetSource// 也就是说Spring最终代理的  是放进去TargetSource让它去处理public void setTarget(Object target) {setTargetSource(new SingletonTargetSource(target));}@Overridepublic void setTargetSource(@Nullable TargetSource targetSource) {this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);}... 其它实现略过,基本都是实现Advised接口的内容//将之前注入到advisorChain中的advisors转换为MethodInterceptor和InterceptorAndDynamicMethodMatcher集合(放置了这两种类型的数据)// 这些MethodInterceptor们最终在执行目标方法的时候  都是会执行的public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {// 以这个Method生成一个key,准备缓存 // 此处小技巧:当你的key比较复杂事,可以用类来处理。然后重写它的equals、hashCode、toString、compare等方法MethodCacheKey cacheKey = new MethodCacheKey(method);List<Object> cached = this.methodCache.get(cacheKey);if (cached == null) {// 这个方法最终在这 DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice//DefaultAdvisorChainFactory:生成通知器链的工厂,实现了interceptor链的获取过程cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);// 此处为了提供效率,相当于把该方法对应的拦截器们都缓存起来,加速后续调用得速度this.methodCache.put(cacheKey, cached);}return cached;}
}//DefaultAdvisorChainFactory:生成拦截器链
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {@Overridepublic List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {// 拿到代理里面所有的通知们:getAdvisorsList<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();for (Advisor advisor : config.getAdvisors()) {if (advisor instanceof PointcutAdvisor) {// Add it conditionally.PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {MethodInterceptor[] interceptors = registry.getInterceptors(advisor);MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {// 动态匹配if (mm.isRuntime()) {// Creating a new object instance in the getInterceptors() method// isn't a problem as we normally cache created chains.for (MethodInterceptor interceptor : interceptors) {interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));}}// 静态匹配else {interceptorList.addAll(Arrays.asList(interceptors));}}}}else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor;if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}else {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}return interceptorList;}
}

AdvisorAdapter

spring aop框架对BeforeAdvice、AfterAdvice、ThrowsAdvice三种通知类型的支持实际上是借助适配器模式来实现的,这样的好处是使得框架允许用户向框架中加入自己想要支持的任何一种通知类型

AdvisorAdapter是一个适配器接口,它定义了自己支持的Advice类型,并且能把一个Advisor适配成MethodInterceptor(这也是AOP联盟定义的借口),以下是它的定义

public interface AdvisorAdapter {// 判断此适配器是否支持特定的Advice  boolean supportsAdvice(Advice advice);  // 将一个Advisor适配成MethodInterceptor  MethodInterceptor getInterceptor(Advisor advisor);  
}

一般我们自己并不需要自己去提供此接口的实现(除非你还行适配被的Advice进来),因为Spring为我们提供了对应的实现:
在这里插入图片描述
实现也非常的简单,如下:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {@Overridepublic boolean supportsAdvice(Advice advice) {return (advice instanceof MethodBeforeAdvice);}@Overridepublic MethodInterceptor getInterceptor(Advisor advisor) {MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();return new MethodBeforeAdviceInterceptor(advice);}}// 都转为了AOP联盟的MethodInterceptor 从而实现拦截统一的拦截工作
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {private MethodBeforeAdvice advice;/*** Create a new MethodBeforeAdviceInterceptor for the given advice.* @param advice the MethodBeforeAdvice to wrap*/public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());// 最终调用,实现了链式调用的效果return mi.proceed();}}

参考:AdvisorAdapterRegistryDefaultAdvisorAdapterRegistry,GlobalAdvisorAdapterRegistry用于管理管理AdvisorAdapter的

如果我们想把自己定义的AdvisorAdapter注册到spring aop框架中,怎么办?

  1. 把我们自己写好得AdvisorAdapter放进Spring IoC容器中
  2. 配置一个AdvisorAdapterRegistrationManager,它是一个BeanPostProcessor,它会检测所有的Bean。若是AdvisorAdapter类型,就:this.advisorAdapterRegistry.registerAdvisorAdapter((AdvisorAdapter) bean);

TargetSource

该接口代表一个目标对象,在aop调用目标对象的时候,使用该接口返回真实的对象。
比如它有其中两个实现SingletonTargetSourcePrototypeTargetSource代表着每次调用返回同一个实例,和每次调用返回一个新的实例

TargetClassAware

所有的Aop代理对象或者代理工厂(proxy factory)都要实现的接口,该接口用于暴露出被代理目标对象类型;

public interface TargetClassAware {// 返回被代理得目标类型  AopUtils#getTargetClass(Object)@NullableClass<?> getTargetClass();
}

AspectMetadata:Metadata for an AspectJ aspect class

表示一个切面的元数据类。

public class AspectMetadata implements Serializable {private final String aspectName;private final Class<?> aspectClass;// AjType这个字段非常的关键,它表示有非常非常多得关于这个切面的一些数据、方法(位于org.aspectj下)private transient AjType<?> ajType;// 解析切入点表达式用的,但是真正的解析工作为委托给`org.aspectj.weaver.tools.PointcutExpression`来解析的//若是单例:则是Pointcut.TRUE  否则为AspectJExpressionPointcutprivate final Pointcut perClausePointcut;public AspectMetadata(Class<?> aspectClass, String aspectName) {this.aspectName = aspectName;Class<?> currClass = aspectClass;AjType<?> ajType = null;// 此处会一直遍历到顶层知道Object  直到找到有一个是Aspect切面就行,然后保存起来// 因此我们的切面写在父类上 也是欧克的while (currClass != Object.class) {AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass);if (ajTypeToCheck.isAspect()) {ajType = ajTypeToCheck;break;}currClass = currClass.getSuperclass();}// 由此可见,我们传进来的Class必须是个切面或者切面的子类的~~~if (ajType == null) {throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");}// 显然Spring AOP目前也不支持优先级的声明。。。if (ajType.getDeclarePrecedence().length > 0) {throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP");}this.aspectClass = ajType.getJavaClass();this.ajType = ajType;// 切面的处在类型:PerClauseKind  由此可议看出,Spring的AOP目前只支持下面4种 switch (this.ajType.getPerClause().getKind()) {case SINGLETON:// 如国是单例,这个表达式返回这个常量this.perClausePointcut = Pointcut.TRUE;return;case PERTARGET:case PERTHIS:// PERTARGET和PERTHIS处理方式一样  返回的是AspectJExpressionPointcutAspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();ajexp.setLocation(aspectClass.getName());//设置好 切点表达式ajexp.setExpression(findPerClause(aspectClass));ajexp.setPointcutDeclarationScope(aspectClass);this.perClausePointcut = ajexp;return;case PERTYPEWITHIN:// Works with a type pattern// 组成的、合成得切点表达式~~~this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));return;default:// 其余的Spring AOP暂时不支持throw new AopConfigException("PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);}}private String findPerClause(Class<?> aspectClass) {String str = aspectClass.getAnnotation(Aspect.class).value();str = str.substring(str.indexOf('(') + 1);str = str.substring(0, str.length() - 1);return str;}...public Pointcut getPerClausePointcut() {return this.perClausePointcut;}// 判断perThis或者perTarger,最单实例、多实例处理public boolean isPerThisOrPerTarget() {PerClauseKind kind = getAjType().getPerClause().getKind();return (kind == PerClauseKind.PERTARGET || kind == PerClauseKind.PERTHIS);}// 是否是within的public boolean isPerTypeWithin() {PerClauseKind kind = getAjType().getPerClause().getKind();return (kind == PerClauseKind.PERTYPEWITHIN);}// 只要不是单例的,就都属于Lazy懒加载,延迟实例化的类型~~~~public boolean isLazilyInstantiated() {return (isPerThisOrPerTarget() || isPerTypeWithin());}
}

Spring AOP切面实例化模型

Spring AOP支持AspectJ的singleton、perthis、pertarget、pertypewithin实例化模型(目前不支持percflow、percflowbelow) 参见枚举类PerClauseKind

  1. singleton:即切面只会有一个实例;
  2. perthis:每个切入点表达式匹配的连接点对应的AOP对象(代理对象)都会创建一个新切面实例
  3. pertarget:每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例
  4. pertypewithin

默认是singleton实例化模型,Schema风格只支持singleton实例化模型,而@AspectJ风格支持这三种实例化模型

singleton:使用@Aspect()指定,即默认就是单例实例化模式,在此就不演示示例了
perthis:每个切入点表达式匹配的连接点对应的AOP代理对象都会创建一个新的切面实例,使用@Aspect("perthis(切入点表达式)")指定切入点表达式;

// 他将为每个被切入点表达式匹配上的代理对象,都创建一个新的切面实例(此处允许HelloService是接口)
@Aspect("perthis(this(com.fsx.HelloService))") 

pertarget:每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例,使用@Aspect("pertarget(切入点表达式)")指定切入点表达式; 此处要求HelloService不能是接口

另外需要注意一点:若在Spring内要使用perthis和pertarget,请把切面的Scope定义为:prototype

AspectInstanceFactory:切面工厂

专门为切面创建实例的工厂(因为切面也不一定是单例的,也支持各种多例形式。上面已有说明)

// 它实现了Order接口哦~~~~支持排序的
public interface AspectInstanceFactory extends Ordered {//Create an instance of this factory's aspect.Object getAspectInstance();//Expose the aspect class loader that this factory uses.@NullableClassLoader getAspectClassLoader();
}

它的实现类如下:
在这里插入图片描述
SimpleAspectInstanceFactory:根据切面的aspectClass,调用空构造函数反射.newInstance()创建一个实例(备注:构造函数private的也没有关系)
SingletonAspectInstanceFactory:这个就更简单了,因为已经持有aspectInstance得引用了,直接return即可

MetadataAwareAspectInstanceFactory

AspectInstanceFactory的子接口。提供了获取AspectMetadata的方法

public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {AspectMetadata getAspectMetadata();// Spring4.3提供  和beanFactory.getSingletonMutex()  否则一般都是thisObject getAspectCreationMutex();
}

SimpleMetadataAwareAspectInstanceFactorySingletonMetadataAwareAspectInstanceFactory已经直接关联到AspectMetadata,所以直接return即可。
LazySingletonAspectInstanceFactoryDecorator也只是个简单的装饰而已。

BeanFactoryAspectInstanceFactory

这个就和Bean工厂有关了。比较重要

public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, Serializable {// 持有对Bean工厂的引用private final BeanFactory beanFactory;// 需要处理的名称private final String name;private final AspectMetadata aspectMetadata;// 传了Name,type可议不传,内部判断出来public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name) {this(beanFactory, name, null);}public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name, @Nullable Class<?> type) {this.beanFactory = beanFactory;this.name = name;Class<?> resolvedType = type;// 若没传type,就去Bean工厂里看看它的Type是啥  type不能为null~~~~if (type == null) {resolvedType = beanFactory.getType(name);Assert.notNull(resolvedType, "Unresolvable bean type - explicitly specify the aspect class");}// 包装成切面元数据类this.aspectMetadata = new AspectMetadata(resolvedType, name);}// 此处:切面实例 是从Bean工厂里获取的  需要注意// 若是多例的,请注意Scope的值@Overridepublic Object getAspectInstance() {return this.beanFactory.getBean(this.name);}@Override@Nullablepublic ClassLoader getAspectClassLoader() {return (this.beanFactory instanceof ConfigurableBeanFactory ?((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :ClassUtils.getDefaultClassLoader());}@Overridepublic AspectMetadata getAspectMetadata() {return this.aspectMetadata;}@Override@Nullablepublic Object getAspectCreationMutex() {if (this.beanFactory.isSingleton(this.name)) {// Rely on singleton semantics provided by the factory -> no local lock.return null;}else if (this.beanFactory instanceof ConfigurableBeanFactory) {// No singleton guarantees from the factory -> let's lock locally but// reuse the factory's singleton lock, just in case a lazy dependency// of our advice bean happens to trigger the singleton lock implicitly...return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex();}else {return this;}}@Overridepublic int getOrder() {Class<?> type = this.beanFactory.getType(this.name);if (type != null) {if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();}// 若没实现接口,就拿注解的值return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);}return Ordered.LOWEST_PRECEDENCE;}
}
PrototypeAspectInstanceFactory:多例专用的工厂 若是多例的,推荐使用
public class PrototypeAspectInstanceFactory extends BeanFactoryAspectInstanceFactory implements Serializable {public PrototypeAspectInstanceFactory(BeanFactory beanFactory, String name) {super(beanFactory, name);// 若是单例,直接报错了if (!beanFactory.isPrototype(name)) {throw new IllegalArgumentException("Cannot use PrototypeAspectInstanceFactory with bean named '" + name + "': not a prototype");}}
}

下面介绍下aspectj这个jar包下几个重要的类




介绍org.aspectj包下的几个类(单独导入的Jar包)

AjTypeSystem:从@Aspect的Class到AjType的工具类

public class AjTypeSystem {// 每个切面都给缓存上   注意:此处使用的是WeakReference 一定程度上节约内存private static Map<Class, WeakReference<AjType>> ajTypes = Collections.synchronizedMap(new WeakHashMap<Class,WeakReference<AjType>>());public static <T> AjType<T> getAjType(Class<T> fromClass) {WeakReference<AjType> weakRefToAjType =  ajTypes.get(fromClass);if (weakRefToAjType!=null) {AjType<T> theAjType = weakRefToAjType.get();if (theAjType != null) {return theAjType;} else {// 其实只有这一步操作:new AjTypeImpl~~~  AjTypeImpl就相当于代理了Class的很多事情~~~~theAjType = new AjTypeImpl<T>(fromClass);ajTypes.put(fromClass, new WeakReference<AjType>(theAjType));return theAjType;}}// neither key nor value was foundAjType<T> theAjType =  new AjTypeImpl<T>(fromClass);ajTypes.put(fromClass, new WeakReference<AjType>(theAjType));return theAjType;}
}

AjType

// 它继承自Java得Type和AnnotatedElement  它自己还提供了非常非常多的方法,基本都是获取元数据的一些方法,等到具体使用到的时候再来看也可以
public interface AjType<T> extends Type, AnnotatedElement {...
}

AjTypeImpl

AjTypeImpl是AjType的唯一实现类,因为方法实在是太多了,因此下面我只展示一些觉得比较有意思的方法实现:

public class AjTypeImpl<T> implements AjType<T> {private static final String ajcMagic = "ajc$";// 它真正传进来的,只是这个class,它是一个标注了@Aspect注解的Class类private Class<T> clazz;private Pointcut[] declaredPointcuts = null;private Pointcut[] pointcuts = null;private Advice[] declaredAdvice = null;private Advice[] advice = null;private InterTypeMethodDeclaration[] declaredITDMethods = null;private InterTypeMethodDeclaration[] itdMethods = null;private InterTypeFieldDeclaration[] declaredITDFields = null;private InterTypeFieldDeclaration[] itdFields = null;private InterTypeConstructorDeclaration[] itdCons = null;private InterTypeConstructorDeclaration[] declaredITDCons = null;// 唯一的一个构造函数public AjTypeImpl(Class<T> fromClass) {this.clazz = fromClass;}// 这个方法有意思的地方在于:它把所有的接口类,都变成AjType类型了public AjType<?>[] getInterfaces() {Class<?>[] baseInterfaces = clazz.getInterfaces();return toAjTypeArray(baseInterfaces);}private AjType<?>[] toAjTypeArray(Class<?>[] classes) {AjType<?>[] ajtypes = new AjType<?>[classes.length];for (int i = 0; i < ajtypes.length; i++) {ajtypes[i] = AjTypeSystem.getAjType(classes[i]);}return ajtypes;}// 就是把clazz返回出去public Class<T> getJavaClass() {return clazz;}public AjType<? super T> getSupertype() {Class<? super T> superclass = clazz.getSuperclass();return superclass==null ? null : (AjType<? super T>) new AjTypeImpl(superclass);}// 判断是否是切面,就看是否有这个注解~~public boolean isAspect() {return clazz.getAnnotation(Aspect.class) != null;}// 这个方法很重要:PerClause AspectJ切面的表现形式// 备注:虽然有这么多(参考这个类PerClauseKind),但是Spring AOP只支持前三种~~~public PerClause getPerClause() {if (isAspect()) {Aspect aspectAnn = clazz.getAnnotation(Aspect.class);String perClause = aspectAnn.value();if (perClause.equals("")) {// 如果自己没写,但是存在父类的话并且父类是切面,那就以父类的为准~~~~if (getSupertype().isAspect()) {return getSupertype().getPerClause();} // 不写默认是单例的,下面的就不一一解释了return new PerClauseImpl(PerClauseKind.SINGLETON);} else if (perClause.startsWith("perthis(")) {return new PointcutBasedPerClauseImpl(PerClauseKind.PERTHIS,perClause.substring("perthis(".length(),perClause.length() - 1));} else if (perClause.startsWith("pertarget(")) {return new PointcutBasedPerClauseImpl(PerClauseKind.PERTARGET,perClause.substring("pertarget(".length(),perClause.length() - 1));				} else if (perClause.startsWith("percflow(")) {return new PointcutBasedPerClauseImpl(PerClauseKind.PERCFLOW,perClause.substring("percflow(".length(),perClause.length() - 1));								} else if (perClause.startsWith("percflowbelow(")) {return new PointcutBasedPerClauseImpl(PerClauseKind.PERCFLOWBELOW,perClause.substring("percflowbelow(".length(),perClause.length() - 1));} else if (perClause.startsWith("pertypewithin")) {return new TypePatternBasedPerClauseImpl(PerClauseKind.PERTYPEWITHIN,perClause.substring("pertypewithin(".length(),perClause.length() - 1));				} else {throw new IllegalStateException("Per-clause not recognized: " + perClause);}} else {return null;}}public AjType<?>[] getAjTypes() {Class[] classes = clazz.getClasses();return toAjTypeArray(classes);}public Field getDeclaredField(String name) throws NoSuchFieldException {Field f =  clazz.getDeclaredField(name);if (f.getName().startsWith(ajcMagic)) throw new NoSuchFieldException(name);return f;}// 这个有点意思:表示标注了@Before、@Around注解的并不算真的方法了,不会给与返回了public Method[] getMethods() {Method[] methods = clazz.getMethods();List<Method> filteredMethods = new ArrayList<Method>();for (Method method : methods) {if (isReallyAMethod(method)) filteredMethods.add(method);}Method[] ret = new Method[filteredMethods.size()];filteredMethods.toArray(ret);return ret;}private boolean isReallyAMethod(Method method) {if (method.getName().startsWith(ajcMagic)) return false;if (method.getAnnotations().length==0) return true;if (method.isAnnotationPresent(org.aspectj.lang.annotation.Pointcut.class)) return false;if (method.isAnnotationPresent(Before.class)) return false;if (method.isAnnotationPresent(After.class)) return false;if (method.isAnnotationPresent(AfterReturning.class)) return false;if (method.isAnnotationPresent(AfterThrowing.class)) return false;if (method.isAnnotationPresent(Around.class)) return false;return true;}// 拿到所有的Pointcut方法  并且保存缓存起来public Pointcut[] getDeclaredPointcuts() {if (declaredPointcuts != null) return declaredPointcuts;List<Pointcut> pointcuts = new ArrayList<Pointcut>();Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {Pointcut pc = asPointcut(method);if (pc != null) pointcuts.add(pc);}Pointcut[] ret = new Pointcut[pointcuts.size()];pointcuts.toArray(ret);declaredPointcuts = ret;return ret;}// 标注有org.aspectj.lang.annotation.Pointcut这个注解的方法。  相当于解析这个注解吧,最终包装成一个PointcutImpl// 主义:Spring-aop也有个接口Pointcut,这里也有一个Pointcut接口  注意别弄混了private Pointcut asPointcut(Method method) {org.aspectj.lang.annotation.Pointcut pcAnn = method.getAnnotation(org.aspectj.lang.annotation.Pointcut.class);if (pcAnn != null) {String name = method.getName();if (name.startsWith(ajcMagic)) {// extract real nameint nameStart = name.indexOf("$$");name = name.substring(nameStart +2,name.length());int nextDollar = name.indexOf("$");if (nextDollar != -1) name = name.substring(0,nextDollar);}return new PointcutImpl(name,pcAnn.value(),method,AjTypeSystem.getAjType(method.getDeclaringClass()),pcAnn.argNames());} else {return null;}}// 最终返回的对象为AdviceImpl实现类public Advice[] getDeclaredAdvice(AdviceKind... ofType) { ... }public Advice[] getAdvice(AdviceKind... ofType) { ... }private void initDeclaredAdvice() {Method[] methods = clazz.getDeclaredMethods();List<Advice> adviceList = new ArrayList<Advice>();for (Method method : methods) {Advice advice = asAdvice(method);if (advice != null) adviceList.add(advice);}declaredAdvice = new Advice[adviceList.size()];adviceList.toArray(declaredAdvice);}// 标注了各个注解的 做对应的处理private Advice asAdvice(Method method) {if (method.getAnnotations().length == 0) return null;Before beforeAnn = method.getAnnotation(Before.class);if (beforeAnn != null) return new AdviceImpl(method,beforeAnn.value(),AdviceKind.BEFORE);After afterAnn = method.getAnnotation(After.class);if (afterAnn != null) return new AdviceImpl(method,afterAnn.value(),AdviceKind.AFTER);AfterReturning afterReturningAnn = method.getAnnotation(AfterReturning.class);if (afterReturningAnn != null) {// 如果没有自己指定注解pointcut()的值,那就取值为value的值吧~~~String pcExpr = afterReturningAnn.pointcut();if (pcExpr.equals("")) pcExpr = afterReturningAnn.value();// 会把方法的返回值放进去、下同。。。   这就是@After和@AfterReturning的区别的原理// 它可议自定义自己的切点表达式咯return new AdviceImpl(method,pcExpr,AdviceKind.AFTER_RETURNING,afterReturningAnn.returning());}AfterThrowing afterThrowingAnn = method.getAnnotation(AfterThrowing.class);if (afterThrowingAnn != null) {String pcExpr = afterThrowingAnn.pointcut();if (pcExpr == null) pcExpr = afterThrowingAnn.value();return new AdviceImpl(method,pcExpr,AdviceKind.AFTER_THROWING,afterThrowingAnn.throwing());}Around aroundAnn = method.getAnnotation(Around.class);if (aroundAnn != null) return new AdviceImpl(method,aroundAnn.value(),AdviceKind.AROUND);return null;}// 必须不是切面才行哦~~~~public boolean isLocalClass() {return clazz.isLocalClass() && !isAspect();}public boolean isMemberClass() {return clazz.isMemberClass() && !isAspect();}// 内部类也是能作为切面哒  哈哈public boolean isMemberAspect() {return clazz.isMemberClass() && isAspect();}public String toString() { return getName(); }
}

总结

工欲善其事必先利其器,任何负责的框架、业务也好。都是由一部分一部分的组件组合而成的。本文主旨就是单独把组件拆出来讲解,逐个击破~~


关注A哥

AuthorA哥(YourBatman)
个人站点www.yourbatman.cn
E-mailyourbatman@qq.com
微 信fsx641385712
活跃平台
公众号BAT的乌托邦(ID:BAT-utopia)
知识星球BAT的乌托邦
每日文章推荐每日文章推荐

BAT的乌托邦


http://chatgpt.dhexx.cn/article/2WJkq11R.shtml

相关文章

Spring AOP名词解释Advice,Pointcut,Advisor,Joinpoint,Advised是什么?

Advice advice解释为通知&#xff0c;需要执行的增强逻辑方法。 advice规范接口如图&#xff0c;分为了before&#xff0c;after等等&#xff0c;为什么没有around呢&#xff0c;因为是通过interceptor实现的。 这里可以看出&#xff0c;AfterAdvice最终会被转换包装成AfterR…

Advised,Advisor,Advice,Pointcut

2019独角兽企业重金招聘Python工程师标准>>> Advised->在Spring中创建了AOP代理之后&#xff0c;就能够使用org.springframework.aop.framework.Advised接口对它们进行管理。 任何AOP代理都能够被转型为这个接口&#xff0c;不论它实现了哪些其它接口 Advisor-&g…

Spring AOP编程官方文档解读之操作Advised对象

Spring AOP编程官方文档解读目录 文章目录 org.springframework.aop.framework.Advised是啥&#xff1f;看一下下面这个类结构图 可以看到无论是ProxyFactoryBean还是ProxyFactory最终都实现了这个接口、这个接口中的方法非常的多&#xff0c;我们随便看一下 public interfac…

arduino知识点梳理(二)——INPUT_PULLUP模式

参考文章1 参考文章2 arduino的引脚模式有三种&#xff1a; INPUT——输入模式OUTPUT——输出模式INPUT_PULLUP——输入上拉模式 Arduino 微控制器自带内部上拉电阻。如果需要使用内部上拉电阻&#xff0c;则应使用pinMode()将引脚设置为输入上拉&#xff08;INPUT_PULLUP&am…

Pull Up Field(字段上移)

两个子类拥有形同的字段 重构&#xff1a;将该字段移至超类

HAL库 output level 和 pull up/ pull down 的区别

从标准库过来的朋友可能对这两个选型有点分不清除 GPIO output level 即输出模式下初始化后端口的电位(高或低) GPIO Pull-up/Pull-down 即输入模式下的电位&#xff0c;例如按键检测

处理概括关系之一 :Pull Up Field(值域上移)

两个subclasses 拥有相同的值域。 将此一值域移至superclass。 动机&#xff08;Motivation&#xff09; 如果各个subclass 是分别开发的&#xff0c;或者是在重构过程中组合起来的&#xff0c;你常会发现它们拥有重复特性&#xff0c;特别是值域更容易重复。这样的值域有时拥有…

Push pull, open drain circuit, pull up, pull down resistor

Push pull 就以下面這個 電路來說&#xff0c; 因為沒有 pull up resistor&#xff0c; 所以 output voltage 由 low 往 high 的速度會較快。有兩個電晶體&#xff0c;一個on&#xff0c;一個 off&#xff0c; 可以 current sourcing&#xff0c;也可以 current sinking&#x…

上拉(Pull Up )或下拉(Pull Down)电阻详解

上拉&#xff08;Pull Up &#xff09;或下拉&#xff08;Pull Down&#xff09;电阻&#xff08;两者统称为“拉电阻”&#xff09;最基本的作用是&#xff1a;将状态不确定的信号线通过一个电阻将其箝位至高电平&#xff08;上拉&#xff09;或低电平&#xff08;下拉&#x…

BetterScroll 2.x 的 pulldown 使用、pullup使用

官方文档&#xff1a;https://better-scroll.github.io/docs/zh-CN/plugins/ BetterScrol滚动原理 有唯一的子节点子节点必须超出包裹的高度new BScroll&#xff08;‘容器名’&#xff09; html内容必须已经渲染完成 绿色部分为 wrapper&#xff0c;也就是父容器&#xff…

【超详细】output level 和 pull up/ pull down 的真正区别

目录 【超详细】output level 和 pull up/ pull down 的真正区别1. Output Level2. Pull up/ Pull down3. 两者的区别1&#xff09;对于Output口来说2&#xff09;而对于Input口来说 总结参考资料 【超详细】output level 和 pull up/ pull down 的真正区别 今天在使用stm32f1…

OUTPUT,INPUT,INPUT_PULLUP三种模式的区别

一&#xff0c;首先三种模式都需要由pinMode()函数来设置。 &#xff08;1&#xff09;设置引脚 为输出&#xff08;OUTPUT&#xff09;模式&#xff0c;此时引脚为低阻抗状态&#xff0c;可以向其他电路原件提供电流&#xff08;通常为40mA以内&#xff09; &#xff08;2&a…

Pull Up Method(函数上移)

动机 避免行为重复是很重要的。尽管重复的两个函数也可以各自工作得很好&#xff0c;但重复自身只会成为错误的滋生地&#xff0c;此外别无价值。无论何时&#xff0c;只要系统之内出现重复&#xff0c;你就会面临“修改其中一个却未能修改另一个”的风险。通常&#xff0c;找…

GPIO_PULLUP,PULLDOWN, NOPULL

NOPULL: 对于输出IO&#xff0c;配置为NOPULL&#xff0c;当IO输出高电平时&#xff0c;IO为1&#xff0c; 当IO输出低电平时&#xff0c;IO为0&#xff1b; PULLUP&#xff1a; 对于输入IO, 默认为高电平&#xff0c;当需要改变为低电平时配置为PULLUP。 比如&#xff1a;K…

pullup和pulldown在verilog中的使用方法

0 前言 这段时间涉及到了IO-PAD&#xff0c;在IO-PAD的RTL的时候注意到了pullup和pulldown&#xff0c;对这个知识比较好奇&#xff0c;就研究了一下&#xff0c;顺便记录下来&#xff0c;IO-PAD的内容等我再研究研究再考虑记录吧 >_< 1 pullup和pulldown的介绍 pullu…

电阻(4)之上拉电阻与下拉电阻详解

原文地址点击这里: 上拉(Pull Up )或下拉(Pull Down)电阻(两者统称为“拉电阻”)最基本的作用是:将状态不确定的信号线通过一个电阻将其箝位至高电平(上拉)或低电平(下拉),无论它的具体用法如何,这个基本的作用都是相同的,只是在不同应用场合中会对电阻的阻值…

解决安装文件时2502、2503错误

在安装文件时有时会出现2502、2503错误&#xff0c;重复安装也不会有什么改变&#xff0c;让人很是头疼。这种问题一般是权限的问题导致的&#xff0c;一般有两种解决办法&#xff0c;第一种就是提升当前用户的权限&#xff0c;第二种就是直接使用CMD安装&#xff0c;这里主要说…

java卸载错误2503_修复控制面板卸载程序时提示错误代码2502、2503的方法

在平常生活中大家是如何卸载软件的呢&#xff1f;有的用户会使用第三方工具&#xff0c;例如软件管家等来进行卸载&#xff0c;这样操作的用户占大多数&#xff0c;但是无法将软件卸载干净。有的用户会直接将安装目录全部删掉&#xff0c;这样操作的用户较少。最理想的卸载软件…

联发科MT2503D处理器详细参数介绍

MT2503D集成了一个ARM7EJ-STM内核&#xff0c;它是运行高级gsm协议软件的主处理器&#xff0c;以及多媒体应用程序、单数字信号处理器核&#xff0c;它管理低层 层次调制解调器和先进的音频功能&#xff0c;嵌入式处理器运行蓝牙基带和链路控制协议和蓝牙无线电控制。 MT 2503…

java内部错误2503_win10安装和卸载Java jdk错误出现2503,2502错误

本人android studio3.0运行helloworld都报错,打开不了守护进程,然后看网上说java版本可能不对,想卸载java,发现任务管理器怎么都卸载不了,网上说的两个办法都试了没用,一天的挣扎,终于找到下面网址的解决办法。 在使用java安装程序时,有时候会出现安装和卸载失败的问题…