1. 概念

1.1 概念

  1. JoinPoint(连接点):需要增强的单个方法;
  2. Advice(通知点): 要执行的增强(方法)及增强执行的时机( before JoinPoint execute?after JoinPoint return?after JoinPoint throwing advice? at advice finally ?)
  3. Pointcut(切点):一条规则,用于指定需要增强的oinPoint
  4. Aspect(切面):符合PointCut的所有JoinPoint以及一个Advice
  5. TargetObject(目标实例):要被多个切面增强的某个实例;
  6. AOP proxy(AOP代理对象): 需要被增强的实例被一系切面修改过后生成的代理对象(Spring 默认使用JDK动态代理和CGlIB生成 相应的代理对象);
  7. Weaving(织入或者叫植入):对目标对象增强的这个行为叫织入(简单的说就是修改Class的字节码用于增强JoinPoint);织入增强代码的时机有三个:编译时,加载时,运行时(Spring是这个)

1.2 Advice类型

public class Proxy {Object target;public Object invoke(Advice advice,Method method,Object [] args){advice.invoke();//before advice,无法阻止线程向下执行到JoinPoint,除非before advice 抛出异常;try{Object result = method.invoke(target,args);//target就是目标对象,是this持有的一个引用指向advice.invoke();//after returning advicez,只要不要抛出异常就会执行return result;} catch(Exception e){advice.invoke();//after throwing advice}finally{advice.invoke(); //after (finally) advice ,一定会被执行JoinPoint的退出方式}}
}

还有一个Around advice 就是这个上面四个advice都执行的的集合体

2. Spring-AOP(Pure Proxy-based Mode)

Spring支持了AspectJ的部分切面语法,在底层默认使用JDK 动态代理和CGLIB 生成目标实例的代理类来完成AOP的操作;

最终代理Bean代码大概形式就是上面描述Advice的代码,这样的结构存在一个比较严重的问题:

target内部自我调用(this.doBusiness(..))被增强的方法会造成Advice失效,比较常见的就是Spring事务管理中事务失效的问题:
事务A方法内部调用自己的事务方法B,B抛出了异常但是B方法造成数据的更改并没有回滚,也就是B方法没有开启事务;
一个解决方法是:A方法内通过AopContext.getCurrentProxy.B(...)来造成B方法的调用;超级难受(:doge;
另一个解决办法是:在Spring Application中启用LoadTimeWeaver相关支持,利用AspectJ lib将运行时的目标类代码进行修改,使得对象的方法字节码就是想要的字节序列

除此之外,

在Spring使用JDK动态代理的时,只能接口方法进行增强;
在Spring使用CGLIB时,会生成目标类的子类,并在子类重写要代理的的方法(只能对非final classs的public protected 最多到default方法进行重写,子类的逻辑是持有一个目标类实例的reference 和MethodInterceptor bean methodInterceptor ,重写所有方法为methodInterceptor.invoke(target,method,args,....)),然后生成子类的实例注入到我们自己编写的类实例中;

2.1 启用@Aspect注解支持

Attention:@Aspect注解支持并不是Spring会在运行时或者其他任何时候修改源代码编译出的字节码(使用AspectJ.jar修改字节码),只是支持@AspectJ的部分切面语法

2.1.1 JavaBean 配置

AppConfig.java:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {}

classpath : 有aspectjweaver.jar;

2.1.2 xml 配置

<aop:aspectj-autoproxy/> + classpath 有aspectjweaver.jar;

2.2 定义一个切面

2.2.1 JavaBean

@Aspect
@Component//注意必须要加上这个注解,不然会scan不到
public class NotVeryUsefulAspect {}

2.2.2 xml

<bean id="myAspect" class="NotVeryUsefulAspect"></bean>

2.3 声明一个切点PointCut

切点的声明分为两个部分: 切点签名(name+参数),一个Aspect表达式; 表达式Pattern,只写最常用的execution吧:

execution : execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?).除了 ret-type, name-pattern,param-pattern必填其他的都是可选项。

例子:

  1. execution(public * com.*.* (..) *?) :匹配com包所有的public的方法;
  2. execution(* com.service.*Service.Insert*(..) ) :匹配com.service包所有的以Service结尾类里面所有的以Insert开头的方法;
  3. execution(* com..*.*(..) :匹配com及其子包下所有的方法;

2.3.1 JavaBean

package com.aruforce.aoptest.aspects;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Aspect
@Component//注意必须要加上这个注解,不然会scan不到
public class BaseAspect {@Pointcut("execution(public * com.aruforce.aoptest.logics.*.*(..))")// indicate by method name;public void anyPublicOperationsInLogicPackage(){} //方法的返回值类型必须是void类型;}

2.3.2 xml

<aop:config><aop:pointcut id="anyPublicOperationsInLogicPackage" expression="execution(public * com.aruforce.aoptest.logics.*.*(..))"></aop:pointcut>
</aop:config>

2.4 增强

2.4.1 声明

BeforAdvice:

package com.aruforce.aoptest.advices;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;@Aspect
@Component //need
public class BeforeExample {@Before("execution(public * com.aruforce.aoptest.logics.*.*(..))")public void doAccessCheck() {// ...}@Before("com.aruforce.aoptest.aspects.BaseAspect.anyPublicOperationsInLogicPackage()")public void doLog(){//.....}//上面两个增强处理的方法集是一样的
}

AfterReturnAdvice:

package com.aruforce.aoptest.advices;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;@Aspect
public class AfterReturnExample {@AfterReturning(pointcut="com.aruforce.aoptest.aspects.BaseAspect.anyPublicOperationsInLogicPackage()",returning="retVal)public void doAccessCheck(Object retVal) {// returning="xxx" 必须和 方法的参数名对应// ...}
}

Around Advice: 尽可能不要使用这个类型的Advice

package com.aruforce.aoptest.advices;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;@Aspect
public class AroundExample {@Around("com.aruforce.aoptest.aspects.BaseAspect.anyPublicOperationsInLogicPackage()")public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {//第一个形参的类型必须是ProceedingJoinPoint// start stopwatchObject retVal = pjp.proceed();//执行被增强的方法// stop stopwatchreturn retVal;}
}

2.4.2 增强的执行顺序(一个JoinPoint上有多个advice需要执行时)

  1. 在多个切面上时:

除非特别声明否则无法决定顺序,aspect 有个order属性,在调用前order值越小越先执行,再返回时order越小越后执行;

  1. 在一个切面的:

无法确定执行顺序,还是考虑怎么合并到一个方法吧

2.5 代理模式的工作机制

2.5.1 关于底层代理技术

  1. Spring优先使用JDK做代理(只要被代理类实现了至少一个接口),只有被代理类完全没有实现任何接口才会使用CGLIB
  2. 如果想全面使用CGLIB,在使用@Aspect形式配置的时候,请使用这个标签<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>,在使用XML配置的时候<aop:config proxy-target-class="true"> </aop:config>,3.2 以后的版本不再需要把CGLIB.jar 加到 classpath.

2.5.2 必须理解Spring AOP是基于代理的这句话的意思

请参看关于Spring-AOP 开头的那段文字,尤其是关于proxy-based aop 的缺陷那段,事务失效的原因分析;

//todo: 什么时候分析下AopNameSpaceHandler的代码,确认下源代码的工作逻辑;

2.6 Configure Sample

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"default-autowire="byName"><context:annotation-config/><context:component-scan base-package="com.aruforce.aoptest"/><!--aspectj-autoproxy 开启@AspectJ 语法支持, --><!--proxy-target-class 代表强制使用CGLIB生成代理类,否则Spring会尽可能使用JDK --><!--expose-proxy 是否允许获取代理对象,如果否AopContext.getCurrentProxy()会抛出异常--><aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

BaseAspect:

package com.aruforce.aoptest.aspects;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;@Aspect
@Component
public class BaseAspect {private Logger logger = LoggerFactory.getLogger(BaseAspect.class);@Pointcut("execution(* com.aruforce.aoptest.logics.*.*(..))")public void allMethod(){}@Before("com.aruforce.aoptest.aspects.BaseAspect.allMethod()")public void doLog(){logger.info("log from methodBuf");}@Around("com.aruforce.aoptest.aspects.BaseAspect.allMethod()&&args(params)")public void doCache(ProceedingJoinPoint proceedingJoinPoint, Object [] params){try {Object proceed = proceedingJoinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}}
}

Job interface:

package com.aruforce.aoptest.logics;public interface Job {public void  test5();public void  test6();
}

TransactiobJob:

package com.aruforce.aoptest.logics;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Component;@Component
public class TransactionJob implements Job{private Logger logger = LoggerFactory.getLogger(TransactionJob.class);public void  test5(){logger.info("test5 for aop");}public void  test6(){logger.info("test6 for aop");//proxy-based make advice in effetive//注意这个proxy,当使用JDK代理接口Job时,不能转型为TransactionJob,当使用CGBLIB时,可以,原因呢?(就是JDK代理和CGLIB代理机制不一样);((Job) AopContext.currentProxy()).test5();// proxy-based,will lose advice// test5();}
}

下面开始写真东西了;


3. Spring AOP(based-aspectJ mode,LTW)

3.1 一个Example

3.1.1 Jar包要求

Attention: spring-agent.jar不是必须的,只是为了在这里说明Command-line启动时的机制,完全可以不用-javaagent来做,Spring做了兼容处理,请参看下面的源码部分)

  1. spring-aspects.jar (这里面有个Aspectj的jar,repackaged)on calsspath;
  2. spring-agent.jar 利用JVM instrumention这个机制,对类加载器注入ClassFileTransformer在类的载入时进行字节码的修改

3.1.2 AspectJ的配置META-INF/aop.xml

Attetion:这是AspectJ的约定必须为classpath/META-INF/aop.xml

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj><weaver options="-verbose -debug -showWeaveInfo"><!--这几个参数应该可以见明知意吧..--><!--设定要进行织入的类pattern--><!--对了,这里有个小坑,不仅要加入要被增强的类还要加入切面这个类BaseApsect,不然会出NoSuchMethodError:***Aspect.aspectOf()--><include within="com.aruforce.aoptest.logics.*"/><include within="com.aruforce.aoptest.aspects.*"/></weaver><aspects><!-- 切面 --><aspect name="com.aruforce.aoptest.aspects.BaseAspect"/></aspects></aspectj>

3.1.3 Spring的配置applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"default-autowire="byName"><context:annotation-config/><context:component-scan base-package="com.aruforce.aoptest"/><!--<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>--><!--开启标签,还可以定义weaver-class,--><context:load-time-weaver aspectj-weaving="autodetect"/><!--解决事务管理中自我调用造成事务失效的问题,注意mode 一定要改成 aspectj--><tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/><!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean>
</beans>

3.1.4 BaseAspect.java

package com.aruforce.aoptest.aspects;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;@Aspect
public class BaseAspect {private Logger logger = LoggerFactory.getLogger(BaseAspect.class);@Pointcut("execution(* com.aruforce.aoptest.logics.TransactionJob.*(..))")public void allMethod() {}@Around("allMethod()")public Object doProfile(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {logger.info("log from methodBuf");try {return proceedingJoinPoint.proceed();} finally {}}
}

3.1.5 事务方法

package com.aruforce.aoptest.logics;public interface Job {public void  test5();public void  test6();
}
package com.aruforce.aoptest.logics;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;@Component
public class TransactionJob implements Job{private Logger logger = LoggerFactory.getLogger(TransactionJob.class);@Transactionalpublic void  test5(){logger.info("test5 for aop");}@Transactionalpublic void  test6(){logger.info("test6 for aop");test5();}
}

3.1.6 Main

public class Main{public void static main(String [] args){ApplicationContext app = new ClassPathXmlApplicationContext("spring-config.xml");Job job1 = (Job)app.getBean("transactionJob");job1.test6();
//      Job job2 = new TransactionJob();
//      job2.test6();}
}

3.1.7 Comman-line

Attention1:注意这一步不是必须的...只是为了说明机制,实际上只需要<context:load-time-weaver aspectj-weaving="autodetect"/> 及 META-INF/aop.xml即可.

Attention2:除了不是必须的外,实际上不建议这么做,-javaagent 实际上时JVM级别的增强,比如在一个tomcat有多个应用的这种情况下,这样启动,BaseAspect会对所有应用的符合切面描述的类进行增强,这绝对不是想要的结果

java -jar HelloWorldAop.Jar -javaagent:pathToSpringAgent.jar

3.1.8 结果(deubg level)

[2019-07-09 11:13:45.981] [DEBUG][org.springframework.jdbc.datasource.DataSourceTransactionManager.getTransaction:371] -Creating new transaction with name [com.aruforce.aoptest.logics.TransactionJob.test6]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
[2019-07-09 11:13:45.981] [DEBUG][org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriver:142] -Creating new JDBC DriverManager Connection to [jdbc:MySql://127.0.0.1:3306/quartz?characterEncoding=UTF-8]
[2019-07-09 11:13:45.990] [DEBUG][org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin:248] -Acquired Connection [com.mysql.jdbc.JDBC4Connection@14751b51] for JDBC transaction
[2019-07-09 11:13:45.990] [DEBUG][org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin:265] -Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@14751b51] to manual commit
[2019-07-09 11:13:45.990] [INFO ][com.aruforce.aoptest.aspects.BaseAspect.doProfile:21] -log from methodBuf
[2019-07-09 11:13:45.990] [INFO ][com.aruforce.aoptest.logics.TransactionJob.test6_aroundBody4:17] -test6 for aop
[2019-07-09 11:13:45.990] [DEBUG][org.springframework.jdbc.datasource.DataSourceTransactionManager.handleExistingTransaction:480] -Participating in existing transaction
[2019-07-09 11:13:45.990] [INFO ][com.aruforce.aoptest.aspects.BaseAspect.doProfile:21] -log from methodBuf
[2019-07-09 11:13:45.991] [INFO ][com.aruforce.aoptest.logics.TransactionJob.test5_aroundBody0:13] -test5 for aop
[2019-07-09 11:13:45.991] [DEBUG][org.springframework.jdbc.datasource.DataSourceTransactionManager.processCommit:763] -Initiating transaction commit
[2019-07-09 11:13:45.991] [DEBUG][org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit:310] -Committing JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@14751b51]
[2019-07-09 11:13:45.991] [DEBUG][org.springframework.jdbc.datasource.DataSourceTransactionManager.doCleanupAfterCompletion:368] -Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@14751b51] after transaction
[2019-07-09 11:13:45.991] [DEBUG][org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection:329] -Returning JDBC Connection to DataSource

补充:

  1. 如果上面的日志开到debug level,你会发现test6()方式再调用test5()时,test5的事务会并入到test6(),而不是像是proxy-base mode 那样test5()就不是个事务

  2. 除了Spring自动注入Bean之外,直接Job job = new TransactionJob();job,test6() 也是会开启一套事务的,代理模式就不行了;

3.2 原理

3.2.1 Spring-config 配置这个Bean:

DefaultContextLoadTimeWeaver:

@Override
public void setBeanClassLoader(ClassLoader classLoader) {LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader);//根据启动环境确定LTW,一般默认就是tomcat了..if (serverSpecificLoadTimeWeaver != null) {this.loadTimeWeaver = serverSpecificLoadTimeWeaver;}else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {// 是用-javaagent:spring-agent.jar 启动的?:org.springframework.instrument.InstrumentationSavingAgent.instrumentation不是NULLthis.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);}else {try {this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);//如果没使用tomcat 也没使用-javaagent的话;}catch (IllegalStateException ex) {throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar");}}
}
protected LoadTimeWeaver createServerSpecificLoadTimeWeaver(ClassLoader classLoader) {String name = classLoader.getClass().getName();try {if (name.startsWith("org.apache.catalina")) {return new TomcatLoadTimeWeaver(classLoader);}else if (name.startsWith("org.glassfish")) {return new GlassFishLoadTimeWeaver(classLoader);}else if (name.startsWith("org.jboss")) {return new JBossLoadTimeWeaver(classLoader);}else if (name.startsWith("com.ibm")) {return new WebSphereLoadTimeWeaver(classLoader)}else if (name.startsWith("weblogic")) {return new WebLogicLoadTimeWeaver(classLoader);}}catch (Exception ex) {}return null;
}
@Override
public void addTransformer(ClassFileTransformer transformer) {this.loadTimeWeaver.addTransformer(transformer);
}

loadTimeWeaver:用tomcat的做个例子吧

public void addTransformer(ClassFileTransformer transformer) {try {this.addTransformerMethod.invoke(this.classLoader, transformer);//在类加载器上执行addClassFileTranFormer实例, 这个Transformer 实际上就是}catch (InvocationTargetException ex) {throw new IllegalStateException("Tomcat addTransformer method threw exception", ex.getCause());}catch (Throwable ex) {throw new IllegalStateException("Could not invoke Tomcat addTransformer method", ex);}
}

3.2.2 怎么调用addClassFiletTransFormer:

ContextNameSpacehandler:

public class ContextNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {......registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());.....}
}

LoadTimeWeaverBeanDefinitionParser: 注入AspectJWeavingEnabler 定义为beanFactoryPostProcessor

class LoadTimeWeaverBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {public static final String ASPECTJ_WEAVING_ENABLER_BEAN_NAME = "org.springframework.context.config.internalAspectJWeavingEnabler";private static final String ASPECTJ_WEAVING_ENABLER_CLASS_NAME = "org.springframework.context.weaving.AspectJWeavingEnabler";private static final String DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME = "org.springframework.context.weaving.DefaultContextLoadTimeWeaver";private static final String WEAVER_CLASS_ATTRIBUTE = "weaver-class";private static final String ASPECTJ_WEAVING_ATTRIBUTE = "aspectj-weaving";@Overrideprotected String getBeanClassName(Element element) {if (element.hasAttribute(WEAVER_CLASS_ATTRIBUTE)) {return element.getAttribute(WEAVER_CLASS_ATTRIBUTE);}return DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME;}@Overrideprotected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {return ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME;// 生成的BeanDefinition的Id ="loadTimeWeaver"}@Overrideprotected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) {if (!parserContext.getRegistry().containsBeanDefinition(ASPECTJ_WEAVING_ENABLER_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);parserContext.registerBeanComponent(new BeanComponentDefinition(def, ASPECTJ_WEAVING_ENABLER_BEAN_NAME));}if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) {new SpringConfiguredBeanDefinitionParser().parse(element, parserContext);}}}protected boolean isAspectJWeavingEnabled(String value, ParserContext parserContext) {if ("on".equals(value)) {return true;}else if ("off".equals(value)) {return false;}else {// check if META-INF/aop.xml if exists or notClassLoader cl = parserContext.getReaderContext().getResourceLoader().getClassLoader();return (cl.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) != null);}}protected boolean isBeanConfigurerAspectEnabled(ClassLoader beanClassLoader) {return ClassUtils.isPresent(SpringConfiguredBeanDefinitionParser.BEAN_CONFIGURER_ASPECT_CLASS_NAME,beanClassLoader);}}

AspectJWeavingEnabler:

public class AspectJWeavingEnabler implements BeanFactoryPostProcessor, BeanClassLoaderAware, LoadTimeWeaverAware, Ordered {public static final String ASPECTJ_AOP_XML_RESOURCE = "META-INF/aop.xml";private ClassLoader beanClassLoader;private LoadTimeWeaver loadTimeWeaver;@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {this.beanClassLoader = classLoader;}@Overridepublic void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {this.loadTimeWeaver = loadTimeWeaver;}@Overridepublic int getOrder() {return HIGHEST_PRECEDENCE;}//AbstractApplicationContext.refresh()--->postProcessBeanFactory(beanFactory);@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {enableAspectJWeaving(this.loadTimeWeaver, this.beanClassLoader);}//这里启用增强public static void enableAspectJWeaving(LoadTimeWeaver weaverToUse, ClassLoader beanClassLoader) {if (weaverToUse == null) {if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader);}else {throw new IllegalStateException("No LoadTimeWeaver available");}}weaverToUse.addTransformer(new AspectJClassBypassingClassFileTransformer(new ClassPreProcessorAgentAdapter()));//AspectJ 的代码增强}private static class AspectJClassBypassingClassFileTransformer implements ClassFileTransformer {private final ClassFileTransformer delegate;public AspectJClassBypassingClassFileTransformer(ClassFileTransformer delegate) {this.delegate = delegate;}@Overridepublic byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {if (className.startsWith("org.aspectj") || className.startsWith("org/aspectj")) {return classfileBuffer;}return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);}}
}

转载于:https://my.oschina.net/Aruforce/blog/3069666

AOP In Spring With LTW相关推荐

  1. AOP和Spring AOP介绍

    AOP和Spring AOP介绍 文章目录 AOP和Spring AOP介绍 一.AOP简介 二. 传统开发存在的弊端 三. AOP实现原理 四.Spring AOP 五.AOP相关术语 一.AOP简 ...

  2. 从AOP到Spring AOP

    文章目录 一.前言 二.AOP基础知识 2.1 AOP 2.1.1 引子:AOP,AOP是什么? 2.1.2 使用对比的方式理解AOP--AOP与OOP 2.1.3 使用对比的方式理解AOP--静态A ...

  3. 【spring 5】AOP:spring中对于AOP的的实现

    在前两篇博客中,介绍了AOP实现的基础:静态代理和动态代理,这篇博客介绍spring中AOP的实现. 一.采用Annotation方式 首先引入jar包:aspectjrt.jar && ...

  4. aopaspect区别_面试官:什么是AOP?Spring AOP和AspectJ的区别是什么?

    AOP(Aspect Orient Programming),它是面向对象编程的一种补充,主要应用于处理一些具有横切性质的系统级服务,如日志收集.事务管理.安全检查.缓存.对象池管理等. AOP实现的 ...

  5. Spring(四)——AOP、Spring实现AOP、Spring整合Mybatis、Spring中的事务管理

    文章目录 1. 什么是AOP 2. 使用Spring实现AOP 2.1 使用Spring的API 接口实现 2.2 自定义实现 2.3 使用注解实现 3. 整合MyBatis 3.1 MyBatis- ...

  6. 使用ProxyFactoryBean创建AOP代理 - Spring Framework reference 2.0.5 参考手册中文版

    http://doc.javanb.com/spring-framework-reference-zh-2-0-5/ch07s05.html 7.5. 使用ProxyFactoryBean创建AOP代 ...

  7. android aop静态方法,spring aop 不能对静态方法进行增强解决

    想要通过aop的方式记录HttpUtils发出的post请求日志,但是 aop 不能对静态方法进行增强.只能对实例方法进行增强.. 如果一定要增强静态方法,我们可以对目标类使用单例模式,然后通过调用实 ...

  8. 2.SSM之Spring整合、AOP及Spring事务

    1.Spring整合 1.1 Mybatis 步骤一:数据库表准备 Mybatis是来操作数据库表,所以先创建一个数据库及表 CREATE DATABASE spring_db CHARACTER S ...

  9. 手写Spring-第十二章-Engage!将AOP和Spring生命周期结合起来

    前言 这里先说一点题外话.由于明年一月份火焰纹章系列新作-火焰纹章Engage就要发售了,我作为一个老火纹厨表示,这个2022年真的一秒钟也待不下去了(恼).所以就用了这么个标题.也算是强行契合了这次 ...

最新文章

  1. 情人节学写html5微信游戏
  2. 常用数据增广方法,解决数据单一问题
  3. Spring Boot 2.x整合Websocket(基于Spring Boot 2.x 前后端分离 iview admin vue 集成activiti工作流...
  4. 贷款被拒,因为你的手机有问题
  5. MySQL工作笔记-编写存储过程批量添加数据
  6. MySQL数据库学习笔记(三)----基本的SQL语句
  7. go语言 os.Rename() cannot move the file to a different disk drive 怎么办
  8. creator 静态属性_cocos creator 属性面板设置
  9. idea中下载插件超时_完美解决idea无法搜索下载插件的问题
  10. Hyper-v下安装网络流量监测图形分析工具 Cacti
  11. Android文件的读写
  12. 记住密码的实现的2个方案
  13. 没想到,快手成了“生产力”
  14. STM32F446高性能MCU芯片介绍
  15. 再不跳槽,应届毕业生拿的都比我多了!
  16. TensorFlow案例---概率学中的逆概率
  17. 对docker一些认知
  18. 微型计算机显示器的标准接口,显示器原理及接口显示器BIOS编程I(原理部分)
  19. 电子游戏销售数据分析(基于Python+Tableau)
  20. 如何迁移操作系统到ssd固态硬盘?

热门文章

  1. 毫米波与视觉融合及车道线检测视频分享
  2. 上海清晖6月PMP认证考前培训,万名PMP见证!
  3. 日语课程0基础学习笔记——第一课
  4. 我的Python学习之路(2)
  5. VS2019 编译+调试 Bullet
  6. [tensorflow] tensorflow书签以及资料整理
  7. 【政府调研】郑州市商务局领导一行莅临中创算力进行指导工作
  8. 亚马逊美国站视频验证注意事项
  9. mnist卷积网络实现
  10. 设计一个circle类成员有半径r求面积和周长的方法_小学数学《圆柱的表面积》说课稿范文...