AspectJ和Spring aop
AspectJ是一个强大的aop框架,可以单独实现静态字节码代理,故而可以用于代理final,abstract方法;而Spring aop是基于动态代理,并且也涵盖了AspectJ实现代理。普通情况下,为了实现方便,都是直接使用spring aop实现动态代理。
Spring创建切面
Spring是在创建bean的时候整理其对应的切面,主要过程如下。
创建入口
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// 创建bean的实例
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// 前置处理器修改beandefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 更早的暴露防止循环引用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
Object exposedObject = bean;
try {
// 填充bean的属性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// !!!初始化bean,这里就是织入切面
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
// 获取单例
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
//获取相关依赖的bean
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
//如果实现了BeanNameAware,BeanClassLoaderAware或者BeanFactoryAware,则调用对应的特殊方法
//setBeanName/setBeanClassLoader/setBeanFactory
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//调用init方法,比如实现了InitializingBean则调用afterPropertiesSet方法;如果自定义了init方法,则反射调用
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//这里执行各类bean前置处理器,此处就含有创建代理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization->
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//如果是基础类(Advice、Pointcut、Advisor、AopInfrastructureBean)则不需要代理
//如果是Aspect类则不需要代理直接跳过
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//!!!创建代理
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;
}
1.普通场景代理
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean->
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//1.先找到所有的切面,主要是a.找到所有advisor定义b.创建advisorc.创建AspectJ的advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//2.再找出匹配上的切面
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//3.看看是不是需要其他辅助切面【AspectJ】
extendAdvisors(eligibleAdvisors);
//4.切面排序(@Order/@Priority)
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
1-c.为AspectJ创建对应的advisor
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
// a.找到所有advisor定义b.创建advisor
List<Advisor> advisors = super.findCandidateAdvisors();
// c.创建AspectJ的advisor
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
c-I.先找到使用了@Aspect注解的类或者使用ajc编译的类
org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
c-II.创建普通Advisor及IntroductionAdvisor
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
//找出该类的所有方法,包含其父类或接口的方法
for (Method method : getAdvisorMethods(aspectClass)) {
//为通知方法创建一个InstantiationModelAwarePointcutAdvisorImpl,如果是普通方法则返回null
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// 如果切面需要懒加载,则在首位加入一个SyntheticInstantiationAdvisor
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// 寻找类中使用@DeclareParents的字段,为之创建DeclareParentsAdvisor
// @DeclareParents可用于AspectJ类的字段上,表示哪些方法需要整合其他方法代理【此处就是将两个毫无关系的类的方法建立关系】
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
2.再找出匹配上的切面
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply->
org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply->
org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class<?>, boolean)
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
// a.IntroductionAdvisor则根据类过滤器匹配
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
// b.PointcutAdvisor匹配切点
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// c.其他则直接匹配成功
return true;
}
}
3.看看是不是需要其他辅助切面【AspectJ】
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#extendAdvisors->
org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
//看是否包含AspectJ通知
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
}
}
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
//添加ExposeInvocationInterceptor,暴露当前的methodInvocation
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
2.根据名字代理
org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator#getAdvicesAndAdvisorsForBean
通过bean的名字来进行匹配,来创建特定代理。
切面执行代理
执行代理的入口
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
因为spring在高版本后,统一使用的Cglib代理,所以在调用方法时,会先为这个方法找到代理链路。然后每个链路依次嵌套调用,实现代理。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//1. 获取切面链路
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
//没有切面则直接执行方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
//2. 创建MethodInvocation,并执行切面
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
//处理返回值
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
执行切面
@Override
@Nullable
public Object proceed() throws Throwable {
// 最后一个切面的时候,如果是public方法(记录的methodProxy),则直接执行方法,否则通过反射的方式执行方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//每次递增使用的切面下标
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 动态匹配【比如参数切点】
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 动态匹配失败,则略过本切面,执行下一个切面
return proceed();
}
}
else {
// 依次调用切面
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
代理顺序
切面的顺序是在创建切面的时候就已经给每个切面排好序了,但是每个Aspect的不同时期的通知是运行时拼接的。
拼接原理
不同的通知,invoke方法不一样,通过调整执行proceed的顺序,保证了各个通知最终能按照一定顺序执行。
AspectJAroundAdvice
直接执行通知方法,所以around在before之前
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}
MethodBeforeAdviceInterceptor
在MethodInvocation执行proceed之前执行before通知
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
AspectJAfterThrowingAdvice
在catch块执行afterThrowing通知
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
AfterReturningAdviceInterceptor
在执行MethodInvocation之后,返回结果前,执行afterReturning通知
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
AspectJAfterAdvice
在finally块执行after通知
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
通知时机顺序总结
按照上述5个通知的执行原理,可以得到以下顺序图。
相关知识点
ExposeInvocationInterceptor
在spring寻找切面的时候,会经过org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary,看是否需要为AspectJ添加一个辅助类——ExposeInvocationInterceptor。
这个特殊切面是用于存储当前的invocation,供AspectJ使用,比如在使用before方法切入,则此时不会直接传入一个invocation,需要通过ExposeInvocationInterceptor来获取当前的invocation。当切面优先级为最高级,则ExposeInvocationInterceptor的会报错,因为没有过这个切面,没有往invocation放入过当前线程的值;由于invocation是threadlocal变量,故而不允许跨线程调用,一旦跨线程也会报错。
那为什么需要ExposeInvocationInterceptor?
因为AspectJ有很多切的时机,除了around的入参是ProceedingJoinPoint以外,其他方法入参都是JointPoint,ProceedingJoinPoint和JoinPoint的区别是前者暴露了MethodInvocation的proceed方法,可以执行方法。所以对于其他时机的切面来说,无法直接获取当前的MethodInvocation,需要通过一个辅助类来帮忙。
PointcutAdvisor和IntroductionAdvisor
Advisor有许多实现,其中PointcutAdvisor和IntroductionAdvisor是主要的两个实现
- PointcutAdvisor是基于切点的,适用范围很广,并且切点很精确
- IntroductionAdvisor是使用于类的,目的是在不修改java文件的情况下,使得某个类具有特殊接口
Pointcut表达式
pointcut表达式十分丰富,从对参数、方法、类、包到注解等都有对应的表达式。多个pointcut之间可以用|| , &&, !进行组合。
args和@args
args:匹配参数;@args匹配含有某些注解的参数
案例:
场景 | 表达式 |
---|---|
没有参数 | args() |
第一个参数是User类型 | args(test.User,…) |
任意参数 | args(…) |
含有具有@RequestBody的参数 | @args(org.springframework.web.bind.annotation.RequestBody) |
execution和@annotation
execution:匹配方法,格式:访问标识符 返回值类型 包路径.类名.方法名(参数类型)
@annotation:匹配具有某些注解的方法
案例:
场景 | 表达式 |
---|---|
所有方法 | execution(* *(…)) |
User类的方法 | execution(public * test.User.*(…)) |
User类最后一个参数是int类型的方法 | execution(public * test.User.*(…,int)) |
within和@within
within:指定包含的类范围;@within:指定具有某些注解的类
案例:
场景 | 表达式 |
---|---|
某个包下所有类方法 | within(test.*) |
具体类的所有方法 | within(test.User) |
使用@Aspect的类的所有方法 | @within(org.aspectj.lang.annotation.Aspect) |
this
匹配代理后的对象的所有方法
案例:
场景 | 表达式 |
---|---|
代理后的对象是User类型 | this(test.User) |
target和@target
target:匹配代理前的对象的所有方法;@target:匹配代理前的对象的类得使用某些注解
案例:
场景 | 表达式 |
---|---|
代理前的对象是User类型 | target(test.User) |
代理前的对象的类使用了@Aspect注解 | @target(org.aspectj.lang.annotation.Aspect) |
Spring aop
Spring的动态代理最终是通过 Cglib和jdk动态代理实现的,分别是为类、接口产生代理类。两者均是在运行时产生代理类,**所以如果是有大量类需要代理时,要考虑下生成的代理类所占空间大小。**因为Cglib是通过字节码技术实现,所以在调用方法时,效率会更高。
jdk代理示例
代理类实现InvocationHandler
总接口:Person
public interface Person {
void printName();
}
实现类:User
@Data
public class User implements Person{
String city;
String name;
@Override
public void printName() {
System.out.println(name);;
}
}
代理类:UserProxy
@Slf4j
public class UserProxy implements InvocationHandler {
User user;
public UserProxy(User user) {
this.user = user;
}
public static Object newProxy(User user) {
UserProxy proxy = new UserProxy(user);
return Proxy.newProxyInstance(UserProxy.class.getClassLoader(), User.class.getInterfaces(), proxy);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("准备执行{}方法", method.getName());
return method.invoke(this.user, args);
}
}
测试代码:
public static void main(String[] args) {
User user = new User();
user.setName("jdk代理");
Person person = (Person) UserProxy.newProxy(user);
person.printName();
}
测试结果
18:56:18.166 [main] INFO cn.dotfashion.soa.CacheDemo.jdk.UserProxy - 准备执行printName方法
jdk代理
cglib代理示例
代理类实现
实体类:User。注意,此类可以不实现接口,因为Cglib是用继承该类User的方式实现。
@Data
public class User implements Person {
String city;
String name;
@Override
public void printName() {
System.out.println(name);;
}
}
代理类:UserProxy
@Slf4j
public class UserProxy implements MethodInterceptor {
User user;
public UserProxy(User user) {
this.user = user;
}
public static Object newProxy(User user) {
UserProxy userProxy = new UserProxy(user);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(user.getClass());
enhancer.setCallback(userProxy);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
log.info("准备执行{}方法", method.getName());
return method.invoke(this.user, args);
}
}
测试代码:
public static void main(String[] args) {
User user = new User();
user.setName("cglib代理");
User pp = (User) UserProxy.newProxy(user);
pp.printName();
}
测试结果:
19:00:30.452 [main] INFO cn.dotfashion.soa.CacheDemo.cglib.UserProxy - 准备执行printName方法
cglib代理
JDK代理 | Cglib代理 | |
---|---|---|
代理类必须实现接口 | 是 | 无要求 |
实现方式 | 通过实现接口,只会对接口的方法进行代理(public/default),生成代理类,然后生成代理对象(Proxy.newProxyInstance),多接口场景更倾向使用jdk代理 | 通过继承代理类,生成子类,覆盖被代理类的方法(非private),通过子类代理对象实现(Enhancer.create) |
代理类实现的接口 | InvocationHandler | MethodInterceptor |