无论是单例 Bean
还是原型 Bean
,对于AOP的实现其实就是依赖于 BeanPostProcessor
的回调,这里主要有个主要的实现类: SmartInstantiationAwareBeanPostProcessor
,这个类即实现了 BeanPostProcessor
,也实现了 InstantiationAwareBeanPostProcessor
。
InstantiationAwareBeanPostProcessor
提供了一个 postProcessorBeforeInstantiation
方法, BeanPostProcessor
提供了一个 postProcessorAfterInitialization
方法。
上面的类图可以看出来入口就是 AbstractAutoProxyCreator
。
AbstractAutoProxyCreator#postProcessBeforeInstantiation
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
在IOC实例化 Bean
之前会调用 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
。
@Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { //3.通过BeanPostProcessor返回代理Bean Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } //4.常规创建bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); return beanInstance; } 复制代码
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
:
@Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { Object cacheKey = getCacheKey(beanClass, beanName); //1.不需要创建代理 if (beanName == null || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } //2.如果是基础设施或者应该跳过的类,则说明这个类不需要创建代理,缓存起来 //默认shouldSkip是false,都不应该跳过 //但是AspectJAwareAdvisorAutoProxyCreator实现了该方法 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } //2.对于自定义的TargetSource会立即创建代理,并缓存 if (beanName != null) { TargetSource targetSource = getCustomTargetSource(beanClass, beanName); //如果不是TargetSource,一般不会走到这里 if (targetSource != null) { 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; } 复制代码
这个方法是在 Bean Instance
之前,判断当前这个 Bean
是否需要生成代理,如果是AOP的基础设施类或者应该跳过的类,则不生成代理;如果是自定义的 targetSource
,则立即生成代理。
因为 AspectJAwareAdvisorAutoProxyCreator
实现了 shouldSkip
方法,而且 AspectJAwareAdvisorAutoProxyCreator
是由 <aop:config/>
转换而来,也就是针对XML的,那也可以说注解方式都不跳过。
shouldSkip
默认是false,即所有的 Bean
都不跳过,现在看下 AspectJAwareAutoProxyCreator
的实现:
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
:
@Override protected boolean shouldSkip(Class<?> beanClass, String beanName) { //1.获取所有的Advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { //对于<aop:aspect/>中的<aop:before/>类似的生成的是AspectJPointcutAdvisor //Advice就是AbstractAspectJAdvice的子类 if (advisor instanceof AspectJPointcutAdvisor) { if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) { return true; } } } return super.shouldSkip(beanClass, beanName); } 复制代码
这个方法获取IOC容器中所有的候选切面,如果 advisor
是 AspectJPointcutAdvisor
并且 advice
是当前类,则返回true,应该跳过,否则调用父类的方式,返回false,不跳过。
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
:
protected List<Advisor> findCandidateAdvisors() { //调用一个工具类 return this.advisorRetrievalHelper.findAdvisorBeans(); } 复制代码
org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
:
public List<Advisor> findAdvisorBeans() { //1.缓存的通知器的名称 String[] advisorNames = this.cachedAdvisorBeanNames; //2.如果cachedAdvisorBeanNames为空,则到容器中查找 //并设置缓存,后续直接使用缓存即可 if (advisorNames == null) { advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } if (advisorNames.length == 0) { return new ArrayList<Advisor>(); } List<Advisor> advisors = new ArrayList<Advisor>(); //3.遍历所有的通知器 for (String name : advisorNames) { if (isEligibleBean(name)) { //4.忽略正在创建的advisor if (this.beanFactory.isCurrentlyInCreation(name)) { if (logger.isDebugEnabled()) { logger.debug("Skipping currently created advisor '" + name + "'"); } } else { //5.从容器中获取Advisor,并添加到advisors中,在这个时候Advisor就被实例化了 advisors.add(this.beanFactory.getBean(name, Advisor.class)); } } } return advisors; } 复制代码
通过一个帮助类 BeanFactoryAdvisorRetrievalHelper
来获取 Advisor
,首先从缓存中获取 advisorNames
,如果不存在则根据类型获取 advisorNames
并放入缓存,然后通过遍历 advisorNames
,从容器中获取 bean
,当然这里如果要获取的 bean
还未被实例化,则会进行实例化,最后返回所有的 Advisor
。这里会忽略 FactoryBean
和正在创建的 Advisor
。
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getCustomTargetSource
:
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) { if (this.customTargetSourceCreators != null && this.beanFactory != null && this.beanFactory.containsBean(beanName)) { for (TargetSourceCreator tsc : this.customTargetSourceCreators) { TargetSource ts = tsc.getTargetSource(beanClass, beanName); if (ts != null) { return ts; } } } return null; } 复制代码
从容器中获取自定义的 TargetSource
,一般默认都是使用 SingletonTargetSource
。
如果不需要跳过,则根据自定义的 TargetSource
立即创建代理, TargetSource
被用来执行 MethodInvocation
的时候获取真正的 target
。所以, proxy
代理的并不是 target
,而是 targetSource
。
通常情况下,一个代理对象只能代理一个 target
,每次调用目标方法也是唯一的 target
。但是如果让 proxy
代理 targetSource
,可以是的每次调用的 target
实例都不同。当然这取决于 targetSource
的实现,这种机制,使得方法的调用更加灵活。
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean
:
protected abstract Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException; 复制代码
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
:
@Override protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { //1.查找合适的通知器 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } 复制代码
获取合适的通知器。
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //1.查找所有的通知器 List<Advisor> candidateAdvisors = findCandidateAdvisors(); //2.筛选可以在该bean上应用的通知器,通过ClassFilter和MethodMatcher对目标类和方法进行匹配 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); //3.扩展操作 extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } 复制代码
获取合适的通知器,主要分为3步:1.查找所有的通知;2.过滤通知;3.扩展通知。
获取通知主要有两种方式:1.基于XML;2.基于注解。
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
这个方法在 shouldSkip
的时候已经执行过了,就是根据所有的 advisorNames
获取所有的 Advisor
,因为 shouldSkip
的时候已经创建过了 advisor bean
,所以这里 getBean
的时候可以直接拿到。
对于注解的,其实就是多调用了一个方法从容器中获取被 @Aspect
注解的类。
@Override protected List<Advisor> findCandidateAdvisors() { //1.调用父类方法查找所有的通知 List<Advisor> advisors = super.findCandidateAdvisors(); //2.解析@Aspect注解,并构建通知 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); return advisors; } 复制代码
在调用 AspectJAwareAdvisorAutoProxyCreator#findCandidateAdvisors
获取所有xml的之后,获取被 @Aspect
注解的类,并转为 Advisor
。
从这个结果可以看出来是使用 AspectJPonitcutAdvisor
,其内部包含了 Advice
和 Pointcut
和 Order
,也就意味着现在拿到了整个应用程序中所有的切面。
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
:
protected List<Advisor> findAdvisorsThatCanApply( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { //调用重载方法 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } } 复制代码
通过一个线程单例进行过滤符合当前Bean的切面。
org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new LinkedList<Advisor>(); for (Advisor candidate : candidateAdvisors) { //1.筛选IntroductionAdvisor的通知器 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; } //2.筛选普通类型通知器 if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } 复制代码
org.springframework.aop.support.AopUtils#canApply
:
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { //1.从通知器中获取ClassFilter,并调用matches进行匹配 return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; //2.对于普通Advisor,这里继续调用重载方法进行筛选 return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { return true; } } 复制代码
org.springframework.aop.support.AopUtils#canApply
:
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); //1.使用ClassFilter匹配Class if (!pc.getClassFilter().matches(targetClass)) { return false; } MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { return true; } IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } //2.查找当前类及其父类的所有Class,只要有一个方法符合,就说明该切面是适用于当前bean的 Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) { //3.获取当前类的方法列表,包括从父类继承而来的 Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { //4.使用methodMatcher匹配方法,匹配成功立即返回 if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || methodMatcher.matches(method, targetClass)) { return true; } } } return false; } 复制代码
上述源码表示了按照切点(Pointcut)对切面(Advisor)的过滤的一个过程,这里有两个重要的类:1. ClassFilter
;2. MethodMatcher
。 ClassFilter
用于根据切点过滤类, MethodMatcher
用于根据切点过滤类的方法,只要某个类中的某个方法符合,那么就说明该切面适用于该 Bean
。
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#extendAdvisors
:
protected void extendAdvisors(List<Advisor> candidateAdvisors) { } 复制代码
默认是一个空实现,交由子类实现。
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#extendAdvisors
:
/** * 将{@link ExposeInvocationInterceptor}添加到通知责任链的开头 * 当使用AspectJ表达式切点和AspectJ样式的通知的时候,这是必须的 */ @Override protected void extendAdvisors(List<Advisor> candidateAdvisors) { AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors); } 复制代码
org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
:
/** * 增加特定的通知器到通知责任链头部,如果责任链包含AspectJ通知器 * 如果不包含AspectJ通知器,则无效 * 目的是暴露当前AOP的调用链,确保JoinPoint可用 */ public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) { // Don't add advisors to an empty list; may indicate that proxying is just not required // 1.如果通知器列表是一个空列表,则啥都不做 if (!advisors.isEmpty()) { boolean foundAspectJAdvice = false; //2.用于检测advisors列表中是否存在AspectJ类型的Advisor或Advice for (Advisor advisor : advisors) { // Be careful not to get the Advice without a guard, as // this might eagerly instantiate a non-singleton AspectJ aspect if (isAspectJAdvice(advisor)) { foundAspectJAdvice = true; } } //3.向advisors列表的首部添加DefaultPointcutAdvisor if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) { advisors.add(0, ExposeInvocationInterceptor.ADVISOR); return true; } } return false; } 复制代码
增加 ExposeInvocationInterceptor
这个拦截器为第一个执行的作用是使用一个线程单例保存了 MethodInvocation
,这个 MethodInvocation
其实就是执行通知和目标方法的对象,当有其他的地方需要这个 MethodInvocation
的时候,就可以通过 ExposeInvocationInterceptor#currentInvocation
获取。
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
:
protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); //1.默认情况下,proxy-target-class=false,使用jdk动态代理 if (!proxyFactory.isProxyTargetClass()) { //判断proxy-target-class属性 if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { //2.检查目标类是否实现了接口,如没有,则设置proxy-target-class=true,使用cglib动态代理 evaluateProxyInterfaces(beanClass, proxyFactory); } } //3.确保所有的都是Advisor Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } //4.创建代理 return proxyFactory.getProxy(getProxyClassLoader()); } 复制代码
为目标对象创建代理类,首先需要判断 proxy-target-class
,这个属性已经看过很多次了,表达代理的方式,如果 proxy-target-class
为false,但是该类没有实现接口,那么也还是使用 CGLIB
代理;然后确保所有的拦截器都是 Advisor
;最后通过 ProxyFactory
创建代理类,并返回存在IOC容器中。
org.springframework.aop.framework.ProxyFactory#getProxy
:
public Object getProxy(ClassLoader classLoader) { //1.先创建AopProxy(DefaultAopProxyFactory会根据条件决定创建哪种AopProxy),然后再创建bean的代理 return createAopProxy().getProxy(classLoader); } 复制代码
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
:
@Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { //1.是否需要优化||代理类型(前面已经设置过了)||是否实现了接口 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); } //2.使用cglib动态代理 return new ObjenesisCglibAopProxy(config); } else { //3.使用jdk动态代理 return new JdkDynamicAopProxy(config); } } 复制代码
org.springframework.aop.framework.CglibAopProxy#getProxy
:
@Override public Object getProxy(ClassLoader classLoader) { //1.从TargetSource获取target的class Class<?> rootClass = this.advised.getTargetClass(); //2.判断是否已经是代理类了 Class<?> proxySuperClass = rootClass; if (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class<?>[] additionalInterfaces = rootClass.getInterfaces(); for (Class<?> additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } //3.CGLIB Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); //4.各种回调 Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } //5.回调过滤 enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); //6.创建代理实例 return createProxyClassAndInstance(enhancer, callbacks); } 复制代码
org.springframework.aop.framework.JdkDynamicAopProxy#getProxy
:
@Override public Object getProxy(ClassLoader classLoader) { Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } 复制代码
获取代理的两种方式:1.JDK;2.CGLIB。当执行AOP的时候,入口也是在这两个类。
AbstractAutoProxyCreator#postProcessAfterInitialization
在 Bean
实例化完成之后,就要执行初始化方法了,这个会调用 BeanPostProcessor
的初始化回调方法,在这里才会真正的生成代理对象,上面的 postProcessorBeforeInstantiation
是在 Bean
实例化之前执行,而且一般不会在这个方法中生成代理对象,而是在该方法中。
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
:
/** * bean初始化后置处理方法 */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { //如果需要,为bean生成代理对象 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } 复制代码
这就是AOP的入口,对于单例 Bean
会在预实例化的时候调用,拿到代理对象,并放入单例的缓存中;对于原型 Bean
,因为没有缓存,每一次调用 Bean
的时候都需要执行该方法判断是否需要生成代理对象。
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
:
/** * 是否需要为目标类生成代理类 */ protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { //1.这两个集合在postProcessorBeforeInitialization中生成的,这里可直接使用 if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } //2.如果是基础设施类(Pointcut、Advice、Advisor等的实现类),或是应该跳过的类 //则不应该生成代理类,直接返回 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } //3.为目标Bean查找合适的通知和通知器 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); //4.如果通知存在,则生成代理 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //5.创建代理 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } //6.通知不存在,直接返回bean this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } 复制代码
可以看到这个真正生成代理对象的方法,也是相同的步骤,调用相同的方法:1.判断基础设施( shouldSkip
);2.查找通知( getAdvicesAndAdvisorsForBean
);3.创建代理( createProxy
)。与上面完全是一模一样的。
总结一下:
1.获取通知。从IOC容器中获取所有的 Advisor
,如果不存在,则创建。
2.过滤通知。根据 Pointcut
的 expression
通过 ClassFilter
和 MethodMatcher
进行过滤,找到可以应用AOP的类及方法。
3.扩展通知。通过 ExposeInvocationInterceptor
的线程单例暴露执行的 MethodInvocation
,以便其他地方使用。
4.创建代理对象。根据 proxy-target-class
选择 JDK
动态代理还是 CGLIB
动态代理,如果 proxy-target-class
为false,但是该类未实现接口,那么依然会使用 CGLIB
动态代理。