目录
1、AOP思想介绍
AOP是Aspect Oriented Programming的缩写,意为面向切面编程,是一种编程思想,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。
2、AOP用途
Spring中基于AOP思想的功能有很多
- 数据库事务控制,也就是我们常用的@Transactional注解;AOP抽取出来的功能有:在开始一系列数据库操作前设置数据库连接的autoCommit属性为false来开启事务,然后等一系列数据库操作完毕后执行commit命令来提交事务,中间出现异常情况则执行rollback命令进行数据库操作回滚。当然Spring的事务机制并非如此简单,还有事务的传播性处理,与ORM框架整合时两边的事务统一处理等功能。
- 缓存控制,也就是我们常用的@Cacheable等注解;AOP抽取出来的功能有:在方法调用前查询是否有缓存信息,是则直接返回缓存内容;在方法调用结束后进行缓存数据增加更新;
- 参数校验 ,也就是我们常用的@Validated注解;AOP抽取出来的功能有:在controller方法调用前,对方法参数进行校验,不符合要求的进行异常抛出等处理;
3、具有相似功能的其他实现方式
- Web项目中的Filter
- Spring MVC的HandlerInterceptor
这两种方式的缺点
- 只支持对http请求进行切面化处理
- 灵活性比较低,无法进行精确的切面配置
4、AOP的实现方式--代理模式
AOP的实现方式为动态代理,常用的动态代理方式有JDK自带的基于接口的动态代理和CGLIB基于字节码修改技术的动态代理。
IOC是AOP的基石,虽然bean的获取也可以像dubbo中那样使用ExtensionLoader进行扩展对象的获取,但是这不符合Spring减少入侵性代码的思想。IOC天然的将bean的创建和获取分开,在BeanFactory进行bean的创建过程中正好可以进行切面的织入以及代理对象生成的工作,而IOC负责将代理对象注入到依赖bean中。
在介绍动态代理前,先介绍一下代理模式,代理模式是常用的设计模式之一,主要用于控制对象的访问,代理模式分静态代理跟动态代理两种,静态代理是通过完全手写代码的方式进行处理如:
/**
* 定义接口
**/
public interface Subject {
void sayHello(String name);
}
/**
* 定义实现类
**/
public class SubjectImpl implements Subject {
@Override
public void sayHello(String name) {
System.out.println("hello " + name);
}
}
/**
**定义代理类
**/
public class SubjectProxyImpl implements Subject {
private Subject subject;
public SubjectProxyImpl() {
this.subject = new SubjectImpl();
}
@Override
public void sayHello(String name) {
System.out.println("before say Hello");
subject.sayHello(name);
System.out.println("after say hello");
}
public static void main(String[] args) {
Subject subject = new SubjectProxyImpl();
subject.sayHello("dddd");
}
}
运行结果为:
静态代理的代码完全手写固定,每增加一个需要代理的类都需要写一套对应的代码,这很显然不是一种高效的方式。所以就有了另外的动态代理方式。
JDK动态代理的核心为Proxy类,他是java反射包下的一个类,创建代理实例的方法为:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
可以看到除了需要传入ClassLoader,接口的Class对象之外还需传入一个InvocationHandler对象,在调用被代理接口的某个方法时,这个InvocationHandler的invoke方法就是在调用代理方法时用于回调。
CGLIB字节码编辑技术的核心类为Enhancer,Enhancer对象需要设置Callback接口对象
/**
* Set the single {@link Callback} to use.
* Ignored if you use {@link #createClass}.
* @param callback the callback to use for all methods
* @see #setCallbacks
*/
public void setCallback(final Callback callback) {
setCallbacks(new Callback[]{callback});
}
/**
* Set the array of callbacks to use.
* Ignored if you use {@link #createClass}.
* You must use a {@link CallbackFilter} to specify the index into this
* array for each method in the proxied class.
* @param callbacks the callback array
* @see #setCallbackFilter
* @see #setCallback
*/
public void setCallbacks(Callback[] callbacks) {
if (callbacks != null && callbacks.length == 0) {
throw new IllegalArgumentException("Array cannot be empty");
}
this.callbacks = callbacks;
}
或者在使用Enhancer的静态方法创建代理对象
/**
* Helper method to create an intercepted object.
* For finer control over the generated instance, use a new instance of <code>Enhancer</code>
* instead of this static method.
* @param type class to extend or interface to implement
* @param callback the callback to use for all methods
*/
public static Object create(Class type, Callback callback) {
Enhancer e = new Enhancer();
e.setSuperclass(type);
e.setCallback(callback);
return e.create();
}
/**
* Helper method to create an intercepted object.
* For finer control over the generated instance, use a new instance of <code>Enhancer</code>
* instead of this static method.
* @param superclass class to extend or interface to implement
* @param interfaces array of interfaces to implement, or null
* @param callback the callback to use for all methods
*/
public static Object create(Class superclass, Class interfaces[], Callback callback) {
Enhancer e = new Enhancer();
e.setSuperclass(superclass);
e.setInterfaces(interfaces);
e.setCallback(callback);
return e.create();
}
/**
* Helper method to create an intercepted object.
* For finer control over the generated instance, use a new instance of <code>Enhancer</code>
* instead of this static method.
* @param superclass class to extend or interface to implement
* @param interfaces array of interfaces to implement, or null
* @param filter the callback filter to use when generating a new class
* @param callbacks callback implementations to use for the enhanced object
*/
public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks) {
Enhancer e = new Enhancer();
e.setSuperclass(superclass);
e.setInterfaces(interfaces);
e.setCallbackFilter(filter);
e.setCallbacks(callbacks);
return e.create();
}
最简单的静态方法需要传入被代理类信息和Callback接口实例。
不管是jdk的InvocationHandler还是Enhancer的Callback接口都给我们提供了一个钩子,通过这个钩子把被代理对象方法的调用交还给我们进行控制,修改一下静态代理的代码来模仿:
静态代理的半动态化版:
public interface Subject {
String sayHello(String name);
}
import java.lang.reflect.Method;
public interface Callback {
Object invoke(Method method, Object[] args, Object realObject);
}
public class SubjectImpl implements Subject {
@Override
public String sayHello(String name) {
System.out.println("hello " + name);
return "ok" +name;
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
public class SubjectProxyImpl implements Subject {
private Subject subject;
private Callback callback;
public SubjectProxyImpl(Callback callback) {
this.subject = new SubjectImpl();
this.callback = callback;
}
@Override
public String sayHello(String name) {
StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
String methodName = stackTraceElement.getMethodName();
Method method = null;
try {
method = subject.getClass().getMethod(methodName, String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return callback.invoke(method, Arrays.asList(name).toArray(), subject).toString();
}
public static void main(String[] args) {
Subject subject = new SubjectProxyImpl(new Callback() {
@Override
public Object invoke(Method method, Object[] args, Object realObject) {
try {
System.out.println("before say hello ");
Object object = method.invoke(realObject, args);
System.out.println("after say Hello ");
return object;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
});
String result = subject.sayHello("dddd");
System.out.println("result is " + result);
}
}
执行结果为:
动态代理的原理方面讲的已经差不多了,其实还有另一种方法达到对应的效果,就是动态编译就像Dubbo中获取Adaptive对象时需要进行动态编译一样,生成静态代理类的完整代码,然后编译成class文件流再进行BeanDefinition注册和bean的创建。这个过程比较繁琐,以后有空的时候再进行尝试。
5、SpringBoot中动态代理详细体系
SpringBoot在autoconfigure包中提供了AopAutoConfiguration
package org.springframework.boot.autoconfigure.aop;
import org.aspectj.weaver.Advice;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} for Spring's AOP support. Equivalent to enabling
* {@link EnableAspectJAutoProxy @EnableAspectJAutoProxy} in your configuration.
* <p>
* The configuration will not be activated if {@literal spring.aop.auto=false}. The
* {@literal proxyTargetClass} attribute will be {@literal true}, by default, but can be
* overridden by specifying {@literal spring.aop.proxy-target-class=false}.
*
* @author Dave Syer
* @author Josh Long
* @since 1.0.0
* @see EnableAspectJAutoProxy
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {
ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}
}
}
默认会被加载配置,除非将其添加到AutoConfiguration的exclude列表中,或者配置spring.aop.auto=false
默认条件化装配的是ClassProxyingConfiguration,未引入aspectjweaver.jar包的情况下。通过AopConfigUtils向BeanDefinitionRegistry注册了InfrastructureAdvisorAutoProxyCreator,并强制设置其proxyTargetClass属性为true,也就是强制使用CGLIB进行动态代理。
而InfrastructureAdvisorAutoProxyCreator通过继承AbstractAdvisorAutoProxyCreator,继承了实现SmartInstantiationAwareBeanPostProcessor的AbstractAutoProxyCreator。
在AbstractAutowireCapableBeanFactory的
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException 方法会在这里进行代理类的创建
刚好是在bean实例化并进行生命周期调用之前。
resolveBeforeInstantiation方法中使用的是InstantiationAwareBeanPostProcessor进行bean的创建处理,而SmartInstantiationAwareBeanPostProcessor是InstantiationAwareBeanPostProcessor的子接口
说明InfrastructureAdvisorAutoProxyCreator从AbstractAutoProxyCreator继承来的postProcessBeforeInstantiation方法被调用了。
在这里进行被代理对象的生成以及代理对象的生成。
getAdvicesAndAdvisorsForBean方法获取的是BeanFactory中适用于当前被代理对象的Advisor bean并排序。
@Override
@Nullable
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();
}
/**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
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;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
完整的方法调用流程中,如果advisor对象同时也是IntroductionAdvisor或者PointcutAdvisor对象时getAdvicesAndAdvisorsForBean方法返回的数组才不为空。
而IntroductionAdvisor和PointcutAdvisor都为接口,都继承了Advisor接口。IntroductionAdvisor有getClassFilter方法,返回ClassFilter对象。PointcutAdvisor有getPointcut方法,返回Pointcut对象,而Pointcut对象中有ClassFilter和MethodMatcher两个属性,很明显都是用于判断某个类是否需要进行动态代理。
创建代理方法如下,这里
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
由代理工厂进行代理创建获取,代理工厂中加入了所有需要织入的切面Advisor。
proxyFactory.getProxy方法中
先创建AopProxy,然后通过AopProxy进行代理创建,而AopProxy又通过AopProxyFactory进行创建,最终调用DefaultAopProxyFactory的方法,确定使用哪种动态代理方式进行处理,对应接口类型和代理类型的代理使用JDK自带动态代理方式,否则使用CGLIB动态代理方式。
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
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.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
可以看到JdkDynamicAopProxy获取代理对象最终回归到Proxy类,ObjenesisCglibAopProxy继承CglibAopProxy获取代理对象最终回归到Enhancer类,只是传入的回调对象(InvocationHandler对象或者Callback对象)都不是我们直接定义任何东西。
InvocationHandler(也就是JdkDynamicAopProxy自己)的invoke方法中将所有Advisor对象转换成调用链,如果调用链为空,则直接通过反射执行方法,返回结果,如果调用链不为空则再次转换为MethodInvocation进行切面代码的执行。最终递归执行方法为ReflectiveMethodInvocation.proceed方法
invokeJoinpoint方法为最后反射执行被代理对象的对应方法,后面两个invoke方法都为MethodInterceptor的invoke方法,而MethodInterceptor接口继承了Interceptor接口,Interceptor接口又继承了Advice接口。
而spring的另一个MethodInterceptor接口实现了Callback接口只有一个intercept方法,CglibAopProxy中有几个这个MethodInterceptor的实现类,如HashCodeInterceptor用于处理对hashCode方法的切面,EqualsInterceptor 用于处理对equals方法的切面,DynamicAdvisedInterceptor则用于处理我们常规定义的切面。DynamicAdvisedInterceptor的intercept方法中可以看到:
逻辑跟JdkDynamicAopProxy.invoke方法中基本相同,CglibMethodInvocation为ReflectiveMethodInvocation的子类,CglibMethodInvocation的proceed方法只是调用了一下父类的proceed方法。
结合静态代理的半动态化版代码,Spring中动态代理实现AOP功能的原理已经差不多明了。
由下往上梳理几个关键接口
整个过程中,只有Advisor是从BeanFactory中批量获取到的,意味着在上面这套体系中我们的切入点就是Advisor,但体系中在确认是Advisor之后,又会以是否为PointcutAdvisor或者IntroductionAdvisor对象进行分类区分处理,所以我们可以通过实现PointcutAdvisor或者IntroductionAdvisor接口的方式来实现AOP功能,最简单的处理方式:
@Component
public class TestAdvisor implements PointcutAdvisor {
@Override
public Pointcut getPointcut() {
return new Pointcut() {
@Override
public ClassFilter getClassFilter() {
return new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
return clazz == TestController.class;
}
};
}
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return true;
}
@Override
public boolean isRuntime() {
return true;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return true;
}
};
}
};
}
@Override
public Advice getAdvice() {
return new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName());
}
};
}
@Override
public boolean isPerInstance() {
return true;
}
}
Pointcut负责判断是否需要动态代理,也就是切面判定,Advice负责处理通知,两者一起组成一个Advisor。其他更细致化的功能介绍如AspectJExpressionPointcut(表达式化定义切面),MethodBeforeAdvice(方法前置通知)等。
以上是Spring提供的基于接口开发的AOP相关功能的实现体系,具有一定的代码入侵性,需要开发者比较了解spring内部的API。
Spring还集成了aspectjweaver基于注解体系的AOP开发方式。
在引入aspectjweaver.jar包的同时需要引入spring-aspects包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
这时候最简单的AOP实现如下:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class TestAop {
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName());
}
}
在引入aspectjweaver包后,AopAutoConfiguration引入的为CglibAutoProxyConfiguration,而CglibAutoProxyConfiguration上的EnableAspectJAutoProxy注解Import引入AspectJAutoProxyRegistrar,AspectJAutoProxyRegistrar通过AopConfigUtils向BeanDefinitionRegistry注册了AnnotationAwareAspectJAutoProxyCreator,并设置其proxyTargetClass属性和exposeProxy属性为EnableAspectJAutoProxy注解配置值,@EnableAspectJAutoProxy注解可以在主引导类上进行手动配置。
AnnotationAwareAspectJAutoProxyCreator除了会将正常的实现Advisor接口的bean同样进行处理,还会将beanFactory中所有有Aspect注解的class进行解析,查找class中带有@Pointcut注解的方法,获取@Pointcut中的切面el表达式信息,包装成AspectJExpressionPointcut,查找class中带有@Around,@Before,@After,@AfterReturning,@AfterThrowing注解的方法并包装成对应的Advice:AspectJAroundAdvice,AspectJMethodBeforeAdvice,AspectJAfterAdvice,AspectJAfterReturningAdvice,AspectJAfterThrowingAdvice,最后组成Advisor:InstantiationModelAwarePointcutAdvisorImpl
有一个小细节:
如何使被代理类的对象能够获取到代理对象?
设置EnableAspectJAutoProxy注解exposeProxy属性为true 或者调用AopConfigUtils.forceAutoProxyCreatorToExposeProxy进行设置。代理对象会被存放到ThreadLocal中,通过AopContext.currentProxy()方法,被代理类的对象中可以获取到代理对象,进行方法调用时切面通知,数据库事务依然正常。