文章目录
- 实现原理
- EnableAspectJAutoProxy
- AnnotationAwareAspectJAutoProxyCreator 代理创建过程
- wrapIfNecessary
- getAdvicesAndAdvisorsForBean
- findCandidateAdvisors
- findAdvisorsThatCanApply
- createProxy
- @AspectJ注解处理
- 代理调用过程
实现原理
本文源码基于spring-aop-5.3.31版本,测试代码如下:
@Aspect
@Component
public class UserAspect {
@Pointcut("execution(* org.example..*..UserService.*(..))")
private void pointcut() {
}
@Around("pointcut()")
public Object aroundUserServiceOperation(ProceedingJoinPoint pjp) throws Throwable { //2
long start = System.currentTimeMillis();
Object retVal = pjp.proceed();
long duration = System.currentTimeMillis() - start;
System.out.printf("time for pointcut method is %d seconds%n", duration);
return retVal;
}
}
@Service
public class UserService {
public String login(String username, String password) {
return String.format(" %s login with password: %s\n", username, password);
}
}
@RestController
@RequestMapping(value = "/api/user")
public class UserController {
@Resource
UserService userService;
@PostMapping("/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
return userService.login(username, password);
}
}
启动类
@SpringBootApplication
@EnableAspectJAutoProxy
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
EnableAspectJAutoProxy
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* 指定代理方式是CGLIB还是基于接口的动态代理
*/
boolean proxyTargetClass() default false;
/**
* 是否暴露代理对象,暴露可以通过AopContext拿到
*/
boolean exposeProxy() default false;
}
导入了这个AspectJAutoProxyRegistrar,实际上是一个ImportBeanDefinitionRegistrar实现。我们知道,@Import + ImportBeanDefinitionRegistrar结合使用的效果就是向容器中注入一些Bean。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* 注册, 配置AspectJ代理
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 这一步就是所有的注册过程
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
通过AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
可以看到
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// AUTO_PROXY_CREATOR_BEAN_NAME
// org.springframework.aop.config.internalAutoProxyCreator
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
从上面的内容来看,AspectJAutoProxyRegistrar的工作就是注册一个AspectJAutoProxyCreator的东西,默认是org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
,如果容器种已经有了一个名称为org.springframework.aop.config.internalAutoProxyCreator
的Bean,那么会优先使用它,否则使用AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator 代理创建过程
AspectJAwareAdvisorAutoProxyCreator的子类,负责处理所有AspectJ注解,以及所有Spring的Advisor。所有AspectJ注解的类都会被自动识别
主要关注点,它是一个BeanPostProcessor
最终org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
找到了Bean的后置处理逻辑
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
// bean 就是被代理对象
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
代理是需要创建代理对象和被代理对象的
wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 下面四个类不会被代理:Advice, Pointcut, Advisor, AopInfrastructureBean
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
getAdvicesAndAdvisorsForBean
对于指定的Bean,获取可用的切面,如果没有切面,则无需生成代理
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator实现了这个方法
@Override
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 找到与beanClass相关联的那些Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findCandidateAdvisors
/**
* Find all candidate Advisors to use in auto-proxying.
* @return the List of candidate Advisors
*/
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
AnnotationAwareAspectJAutoProxyCreator中继承了此方法
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
切面的查找实际上委托给了BeanFactoryAdvisorRetrievalHelper和BeanFactoryAspectJAdvisorsBuilder这两个类来完成的
BeanFactoryAdvisorRetrievalHelper用于从BeanFactory中获取org.springframework.aop.Advisor
接口的实现类,核心逻辑如下(省略了部分不重要的代码)
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 获取所有Advisor类型的Bean名称,同时缓存到 this.cachedAdvisorBeanNames
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
// 忽略正在创建的Bean
if (this.beanFactory.isCurrentlyInCreation(name)) {
// 记录日志
} else {
// ....
advisors.add(this.beanFactory.getBean(name, Advisor.class));
// ....
}
}
}
return advisors;
}
BeanFactoryAspectJAdvisorsBuilder
在项目启动的过程中,项目中的所有切面会被 AnnotationAwareAspectJAutoProxyCreator 解析,它会找到切面中的每一个通知以及通知对应的切点,拿这二者构建一个新的对象,这个对象就是 Advisor。最后将所有解析得到的增强器注入到容器中。
BeanFactoryAspectJAdvisorsBuilder这个类的操作是获取所有Advisor
创建代理
findAdvisorsThatCanApply
此方法的作用是找到目标类可用的Advisor列表
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
} finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
判断Advisor和目标类是否匹配
- IntroductionAdvisor:使用ClassFilter类进行匹配
- PointcutAdvisor:使用Pointcut来进行匹配
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;
}
}
PointCut类型的
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
// AspectJExpressionPointcut
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
AspectJExpressionPointcut是一个MethodMatcher的实现,代表了使用AspectJ注解@Pointcut定义的一个切点,比如:
@Pointcut("execution(* org.example..*..UserService.*(..))")
private void pointcut() {
}
createProxy
找到Advisor之后下一步就是创建代理对象
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()) {
// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
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);
}
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
return proxyFactory.getProxy(classLoader);
}
@AspectJ注解处理
@Aspect注解表示一个AspectJ配置类,里面可以配置切点和切面,以及二者之间的关系
注意:@Aspect在Spring中没有专门定义一个组件去扫描它,因此需要其他额外的配置将@AspectJ配置的那个类放入Spring容器
-
加@Component注解
-
使用@ComponentScan注解
-
如果使用XML配置,可以使用context:component-scan,还需要配置
<context:include-filter/>
,其中context:component-scan这个标签是扫描@Component、@Controller、@Service等这些注解的类,则把这些类注册为bean。它不扫描@Aspect注解的。所以需要在子标签添加 <context:include-filter type="annotation"expression=“org.aspectj.lang.annotation.Aspect”/>
代理调用过程
如果想跟踪Advice是如何执行的,以及Advice执行到被代理类方法执行的过程,该怎么办呢?
仅需要进行简单的设置,即可输出cglib以及jdk动态代理产生的class文件,然后工具查看生成的动态代理类
// 输出cglib动态代理产生的类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
// 输出jdk动态代理产生的类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
基于CGlib的代理类命名方式为:被代理类类名 + $$EnhancerBySpringCGLIB$$ + 8个随机字符,例如:UserService$$EnhancerBySpringCGLIB$$efcfcced
使用jd-gui工具查看反编译的字节码,如下图所示
可以在里面找到login方法
下面将login方法调用的相关内容拿出来看看
import java.lang.reflect.Method;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetClassAware;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Dispatcher;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
public class UserService$$EnhancerBySpringCGLIB$$efcfcced
extends UserService implements SpringProxy, Advised, Factory {
private MethodInterceptor CGLIB$CALLBACK_0;
private static final MethodProxy CGLIB$login$0$Proxy;
private static final Method CGLIB$login$0$Method;
public final String login(String paramString1, String paramString2) {
if (this.CGLIB$CALLBACK_0 == null)
CGLIB$BIND_CALLBACKS(this);
return (this.CGLIB$CALLBACK_0 != null) ?
(String)this.CGLIB$CALLBACK_0.intercept(this,
CGLIB$login$0$Method, new Object[] {
paramString1, paramString2 }, CGLIB$login$0$Proxy)
: super.login(paramString1, paramString2);
}
}
MethodInterceptor是spring-core提供的一个接口
public interface MethodInterceptor extends Callback {
Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}
intercept(Object obj, Method method, Object[] args, MethodProxy proxy)是 MethodInterceptor 的核心方法。在方法被调用时,Spring 会调用此方法,传递如下参数:
- obj:被代理的目标对象,即UserService
- method:被调用的方法,即login方法
- args:方法的参数
- proxy:用于调用目标方法的 MethodProxy 对象
现在只知道CGLIB$CALLBACK_0
是一个MethodInterceptor,但到底是哪个实现呢,我们可以通过Debug查看,如下图所示,可以看到它的实际类型是org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
// this.advised -> ProxyFactory
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);
// 获取拦截器链,即@Around, @Before等修饰的方法
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = invokeMethod(target, method, argsToUse, methodProxy);
}
else {
// We need to create a method invocation...
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);
}
}
}