位置: IT常识 - 正文

Spring AOP 切面增强(springboot aop切面)

编辑:rootadmin
Spring AOP 切面增强 背景

推荐整理分享Spring AOP 切面增强(springboot aop切面),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:spring切面注解方法实现,springboot aop切面,spring的aop的切面是什么意思,springaop切面 切片 切入点理解,spring切面使用,springaop切面 切片 切入点理解,spring切面使用,spring的aop的切面是什么意思,内容如对您有帮助,希望把文章链接给更多的朋友!

背景:我们在开发过程中,经常需要做些周边功能: 性能统计、日志、事物管理。我们需要考虑如何解耦这些周边功能开发和核心业务开发区分开达到提升代码质量目的。

定义

在AOP思想里面定义

周边功能定义是(性能统计、日志、事务管理),被定义成切面。

核心功能和切面功能单独开发。

然后把核心功能和切面功能编织在一起。

核心概念

在AOP概念里,所有的方法称为连接点。

被AOP应用拦截到的方法称为切点。

我们在切点前后添加一段逻辑代码比如方法前、方法后、方法前后。称为增强/通知。

切面是切点和增强/通知总成

织入: 把切面加入对象,并创建代理对象过程叫做织入。 这个工作是由spring完成的。

切点

每个方法都可以称为连接点。

定义增强/通知代码

@Before 目标方法调用前通知

@AfterReturning 目标方法成功返回后通知

@After 目标方法调用之后通知

@AfterThrowing 目标方法抛出异常后通知

@Around 环绕执行

aop简单示例定义业务Servicepublic interface AnswerService {void answerQuestion();}@Service@Slf4jpublic class AnswerServiceImpl implements AnswerService {@Overridepublic void answerQuestion() {Answer answer = new Answer();answer.setId(1L).setAuthor("jiguansheng").setContent("笨笨是好宝宝");log.info(answer.toString());}}定义切面@Component@Aspect@Slf4jpublic class SpringLearnAop {@Pointcut("execution(* com.example.springcorelearn.answer..*(..))")public void definitionPointCut() {}@AfterReturning("definitionPointCut()")public void afterProcess() {log.info("结束了。。。。");}@Before("definitionPointCut()")public void beforeProcess() {log.info("想到我了");}}输出

想到我了Answer(id=1, content=笨笨是好宝宝, author=jiguansheng)结束了。。。。

熟悉Spring AOP之前一定要熟悉Spring ApplicationContext启动流程和bean生命周期。

Spring 工作流程分析postProcessBeforeInstantiation 实例化前处理

创建AnswerService 前置处理。遍历容器所有的类,查找并遍历所有的切面信息。然后将切面信息保存到缓存中。比如案例中的SpringLearnAop。

postProcessAfterInitializaiton 初始化后处理

获得AnswerService 切面信息: 首先从缓存中拿到切面信息和AnswerService 方法。然后找到所有需要进行AOP的方法。

创建AOP代理对象:视AnswerService是否是接口。是接口采用sdk代理。若不是采用cglib代理。

代码入口refresh源码@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();//// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {}finally {}}}@Overridepublic void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {getBean(beanName);}}}// Trigger post-initialization callback for all applicable beans...for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize").tag("beanName", beanName);SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}smartInitialize.end();}}}分析

finishBeanFactoryInitialization 初始化所有关联的非懒加载的单例。

instantiate all remaing (non-lazy-init) singletons

主要调用了preInstantiateSingletons()->beanFactory.getBean,对所有bean实例化操作。

getBean源码// Create bean instance.if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {//}});beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}分析

若bean不存在,调用createBean创建

createBean源码@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {RootBeanDefinition mbdToUse = mbd;Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.mbdToUse.prepareMethodOverrides();try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}分析

resolveBeforeInstantiation

createBean 埋入前置处理器。

postProcessBeforeInstantiation源码@Nullableprotected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}return null;}

而InstantiationAwareBeanPostProcessor 有个类是AnnotationAwareAsepctJAutoProxyCreator 处理。

AnnotationAwareAspectJAutoProxyCreator源码@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {Object cacheKey = getCacheKey(beanClass, beanName);//....if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}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;}分析Spring AOP 切面增强(springboot aop切面)

shouldSkip方法非常重要.由于其等于true。所以还是返回null。

shouldSkip源码@Overrideprotected boolean shouldSkip(Class<?> beanClass, String beanName) {// TODO: Consider optimization by caching the list of the aspect namesList<Advisor> candidateAdvisors = findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor &&((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {return true;}}return super.shouldSkip(beanClass, beanName);}分析

findCandidateAdvisors 非常重要,作用是查询可能的切面信息。

findCandidateAdvisors源码@Overrideprotected 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;}分析

重点是buildAspectJAdvisors方法

buildAspectJAdvisors源码/*** Look for AspectJ-annotated aspect beans in the current bean factory,* and return to a list of Spring AOP Advisors representing them.* <p>Creates a Spring Advisor for each AspectJ advice method.* @return the list of {@link org.springframework.aop.Advisor} beans* @see #isEligibleBean*/public List<Advisor> buildAspectJAdvisors() {List<String> aspectNames = this.aspectBeanNames;if (aspectNames == null) {synchronized (this) {aspectNames = this.aspectBeanNames;if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();aspectNames = new ArrayList<>();//1、取出所有的bean名称String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);//2、遍历所有beanfor (String beanName : beanNames) {if (!isEligibleBean(beanName)) {continue;}// We must be careful not to instantiate beans eagerly as in this case they// would be cached by the Spring container but would not have been weaved.Class<?> beanType = this.beanFactory.getType(beanName, false);if (beanType == null) {continue;}//3、是否是切面类if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);//4、获得切面列表List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);}else {this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}else {// Per target or per this.if (this.beanFactory.isSingleton(beanName)) {throw new IllegalArgumentException("Bean with name '" + beanName +"' is a singleton, but aspect instantiation model is not singleton");}MetadataAwareAspectInstanceFactory factory =new PrototypeAspectInstanceFactory(this.beanFactory, beanName);this.aspectFactoryCache.put(beanName, factory);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}}this.aspectBeanNames = aspectNames;return advisors;}}}if (aspectNames.isEmpty()) {return Collections.emptyList();}List<Advisor> advisors = new ArrayList<>();for (String aspectName : aspectNames) {List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);}else {MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}return advisors;}分析 BeanFactoryUtils.beanNamesForTypeIncludingAncestors

看方法参数是lb、Object.class 。 获取符合类型的所有bean。类型是Object。说明查询所有的beanName

for (String beanName : beanNames) {

Class<?> beanType = this.beanFactory.getType(beanName, false);

this.advisorFactory.isAspect(beanType)

遍历所有的bean,检查其是否是aop切面元数据类。

取出aop切面元数据类的增强通知方法。转化成Advice 类。

存入advisors 集合中。

isAspect源码@Overridepublic boolean isAspect(Class<?> clazz) {return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));}private boolean hasAspectAnnotation(Class<?> clazz) {return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);}分析

判断类是否是切面元数据配置。是否有Aspect 注解

getAdvisors源码@Overridepublic List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();validate(aspectClass);// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator// so that it will only instantiate once.MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List<Advisor> advisors = new ArrayList<>();//getAdvisorMethod 遍历所有方法//查找切点定义方法。for (Method method : getAdvisorMethods(aspectClass)) {Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);if (advisor != null) {advisors.add(advisor);}}// If it's a per target aspect, emit the dummy instantiating aspect.if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);advisors.add(0, instantiationAdvisor);}// Find introduction fields.for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);if (advisor != null) {advisors.add(advisor);}}return advisors;}getAdvisorMethod源码// Exclude @Pointcut methodsprivate static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));private List<Method> getAdvisorMethods(Class<?> aspectClass) {List<Method> methods = new ArrayList<>();ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);if (methods.size() > 1) {methods.sort(adviceMethodComparator);}return methods;}分析

取得类所有增强通知的注解(@After @AfterReturning @Before @Around @AfterThrowing),忽略Pointcut注解

getAdvisor源码@Override@Nullablepublic Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);}InstantiationModelAwarePointcutAdvisorImpl源码public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {//。。。。。if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {//省略去懒加载部分配置代码。}else {// A singleton aspect.this.pointcut = this.declaredPointcut;this.lazy = false;//实例化切面通知this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);}}instantiateAdvice源码private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,this.aspectInstanceFactory, this.declarationOrder, this.aspectName);return (advice != null ? advice : EMPTY_ADVICE);}getAdvice源码public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();validate(candidateAspectClass);AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);if (aspectJAnnotation == null) {return null;}AbstractAspectJAdvice springAdvice;switch (aspectJAnnotation.getAnnotationType()) {case AtPointcut:if (logger.isDebugEnabled()) {logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");}return null;case AtAround:springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;case AtBefore:springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;case AtAfter:springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;case AtAfterReturning:springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();if (StringUtils.hasText(afterReturningAnnotation.returning())) {springAdvice.setReturningName(afterReturningAnnotation.returning());}break;case AtAfterThrowing:springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {springAdvice.setThrowingName(afterThrowingAnnotation.throwing());}break;default:throw new UnsupportedOperationException("Unsupported advice type on method: " + candidateAdviceMethod);}// Now to configure the advice...springAdvice.setAspectName(aspectName);springAdvice.setDeclarationOrder(declarationOrder);String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);if (argNames != null) {springAdvice.setArgumentNamesFromStringArray(argNames);}springAdvice.calculateArgumentBindings();return springAdvice;}分析

按增强通知注解走不同逻辑分支,实例化切面信息。

3、 是否是配置类

advisorFactory.getAdvisors(factory);

postProcessAfterInitializaiton 后置处理源码@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}AbstractAutoProxyCreator源码@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}wrapIfNecessary源码/*** Wrap the given bean if necessary, i.e. if it is eligible for being proxied.* @param bean the raw bean instance* @param beanName the name of the bean* @param cacheKey the cache key for metadata access* @return a proxy wrapping the bean, or the raw bean instance as-is*/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;}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源码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();}分析

findEligibleAdvisors 查询匹配的切面

findEligibleAdvisors源码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;}分析

findCandidateAdvisors 查询匹配切面并返回。

findCandidateAdvisor源码@Overrideprotected 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;}分析

aspectJAdvisorBuilder.buildAspectJAdvisors 读取前置处理的保存的切面信息。

再回到findEligibleAdvisors。

findAdvisorsThatCanApply源码/*** Search the given candidate Advisors to find all Advisors that* can apply to the specified bean.* @param candidateAdvisors the candidate Advisors* @param beanClass the target's bean class* @param beanName the target's bean name* @return the List of applicable Advisors* @see ProxyCreationContext#getCurrentProxiedBeanName()*/protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {ProxyCreationContext.setCurrentProxiedBeanName(beanName);try {return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);}finally {ProxyCreationContext.setCurrentProxiedBeanName(null);}}AopUtils.findAdvisorsThatCanApply源码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 processedcontinue;}//能否应用在answerService上。if (canApply(candidate, clazz, hasIntroductions)) {eligibleAdvisors.add(candidate);}}return eligibleAdvisors;}分析

for (Advisor candidate : candidateAdvisors) {

遍历每一个增强通知。

if (canApply(candidate, clazz, hasIntroductions)) {

评估是否能应用在answerService上。

若匹配上返回候选的增强通知。

canApply源码/*** Can the given advisor apply at all on the given class?* <p>This is an important test as it can be used to optimize out an advisor for a class.* This version also takes into account introductions (for IntroductionAwareMethodMatchers).* @param advisor the advisor to check* @param targetClass class we're testing* @param hasIntroductions whether the advisor chain for this bean includes* any introductions* @return whether the pointcut can apply on any method*/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;}}/*** Can the given pointcut apply at all on the given class?* <p>This is an important test as it can be used to optimize* out a pointcut for a class.* @param pc the static or dynamic pointcut to check* @param targetClass the class to test* @param hasIntroductions whether the advisor chain* for this bean includes any introductions* @return whether the pointcut can apply on any method*/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;}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;}分析

canApply(pca.getPointcut(), targetClass, hasIntroductions)

pca.getPointcut() 取出匹配增强器的切点(pointcut)。

tartgetClass 目标类。

for (Class<?> clazz : classes) { for (Method method : methods) {

取目标类所有的方法和MethodMatcher做决策。是否匹配目标方法。若匹配返回true。

返回 wrapIfNecessary 方法

创建代理源码Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));createProxy源码protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {//省略若干行代码ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);// Use original ClassLoader if bean class not locally loaded in overriding class loaderClassLoader classLoader = getProxyClassLoader();if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();}return proxyFactory.getProxy(classLoader);}分析

简单理解就是 实例化ProxyFactory 代理工厂对象并返回代理类。

getProxy源码public Object getProxy() {return createAopProxy().getProxy();}protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);}DefaultAopProxyFactory.createAopproxy源码@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (!NativeDetector.inNativeImage() &&(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) || ClassUtils.isLambdaClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}分析

决策目标类是否是个接口。是的使用sdk代理 (jdkDnynamicAopProxy)否则采用ObjenesisCglibAopProxy.

本文链接地址:https://www.jiuchutong.com/zhishi/300124.html 转载请保留说明!

上一篇:数据库管理系统(基于前端+后端+数据库)(数据库管理系统能对数据库中的数据进行查询)

下一篇:ChatGPT会取代你的岗位吗?

  • 三星buds2怎么切歌(三星buds2怎么切换歌曲)

    三星buds2怎么切歌(三星buds2怎么切换歌曲)

  • mate30pro支持内存卡扩展吗(mate30pro用的什么内存)

    mate30pro支持内存卡扩展吗(mate30pro用的什么内存)

  • iPhone11有双卡吗(iphone11有双卡双待的吗)

    iPhone11有双卡吗(iphone11有双卡双待的吗)

  • 淘宝投诉撤销后还可以再次投诉吗(淘宝投诉撤销后还能再次发起投诉吗)

    淘宝投诉撤销后还可以再次投诉吗(淘宝投诉撤销后还能再次发起投诉吗)

  • 怎么看抖音好友上线(怎么看抖音好友和谁聊天)

    怎么看抖音好友上线(怎么看抖音好友和谁聊天)

  • 菜鸟驿站一键取件是什么意思(菜鸟驿站一键取件)

    菜鸟驿站一键取件是什么意思(菜鸟驿站一键取件)

  • 苹果8p能当空调遥控器吗(iphone8plus可以当空调遥控器吗)

    苹果8p能当空调遥控器吗(iphone8plus可以当空调遥控器吗)

  • 苹果11黑屏无法唤醒(苹果11黑屏无法接通怎么办)

    苹果11黑屏无法唤醒(苹果11黑屏无法接通怎么办)

  • oppo水滴屏有哪些型号(oppoa系列水滴屏)

    oppo水滴屏有哪些型号(oppoa系列水滴屏)

  • 为什么lofter会跳到淘宝(lofter为什么会影响wifi)

    为什么lofter会跳到淘宝(lofter为什么会影响wifi)

  • 苹果8可以双卡双待吗(苹果8可以双卡不)

    苹果8可以双卡双待吗(苹果8可以双卡不)

  • 微信看小视频卡顿怎么办(微信小视频卡屏解决办法)

    微信看小视频卡顿怎么办(微信小视频卡屏解决办法)

  • lndal40华为什么型号(华为lndtl40)

    lndal40华为什么型号(华为lndtl40)

  • 五类线能用200m宽带吗(五类线能用超五类水晶头吗)

    五类线能用200m宽带吗(五类线能用超五类水晶头吗)

  • 天猫小蜜在哪里找(天猫怎么咨询天猫小蜜)

    天猫小蜜在哪里找(天猫怎么咨询天猫小蜜)

  • ps的渐变工具在哪(ps中的渐变工具在哪里)

    ps的渐变工具在哪(ps中的渐变工具在哪里)

  • 喵喵机怎么打印不出来(喵喵机怎么打印错题)

    喵喵机怎么打印不出来(喵喵机怎么打印错题)

  • 红米note8pro怎么更换主题(红米note8pro怎么降级)

    红米note8pro怎么更换主题(红米note8pro怎么降级)

  • 荣耀9x有没有语音唤醒功能(华为荣耀9x有没有语音控制开启软件)

    荣耀9x有没有语音唤醒功能(华为荣耀9x有没有语音控制开启软件)

  • 支付宝充话费显示暂不支持此号码(支付宝充话费显示备货中)

    支付宝充话费显示暂不支持此号码(支付宝充话费显示备货中)

  • 苹果闪光灯消息怎么开(苹果闪光灯消息怎么关闭)

    苹果闪光灯消息怎么开(苹果闪光灯消息怎么关闭)

  • 抖音可以仅一人可见么(抖音仅一人可见会推送给他吗)

    抖音可以仅一人可见么(抖音仅一人可见会推送给他吗)

  • 小米手环4怎么播放音乐(小米手环4怎么解绑)

    小米手环4怎么播放音乐(小米手环4怎么解绑)

  • 【深度学习时间序列预测案例】零基础入门经典深度学习时间序列预测项目实战(附代码+数据集+原理介绍)

    【深度学习时间序列预测案例】零基础入门经典深度学习时间序列预测项目实战(附代码+数据集+原理介绍)

  • 微擎框架破解版v2.7.10去授权一键安装纯净商业版(微擎纯净框架,无任何限制)-电脑学习网(微擎框架安装教程)

    微擎框架破解版v2.7.10去授权一键安装纯净商业版(微擎纯净框架,无任何限制)-电脑学习网(微擎框架安装教程)

  • 企业固定资产入账新标准
  • 什么是特别纳税人
  • 固定资产的确认条件包括
  • 成本结算怎么处理?
  • 预缴增值税需要预缴附加税吗
  • 补缴以前年度增值税如何做账
  • 利息调整的计算公式
  • 人工费怎么入账
  • 工会福利费列支范围
  • 产品税率下调企业是否要到税务部门备案
  • 个人劳务费增值税如何缴纳
  • 零售商品收入会计分录
  • 个人挂靠公司承接工程如何做会计处理?
  • 公司对公租车保险的规定
  • 水电费没有票怎么做账
  • 水利建设基金有优惠政策吗
  • 场地费开票税率
  • 差额纳税的会计处理
  • 外经证是先开票还是先预缴税款
  • 质保金的税务处理
  • 研发支出与开发成本的区别
  • 转账时开户行写错了钱转出去了对方收不到
  • 商场收取商户违约金上什么税?
  • 公司入职员工
  • 库存现金盘盈的账务处理中可能涉及的科目有
  • 土地使用权出让金收费标准
  • 苹果双系统不小心删了苹果系统
  • 趣谈linux系统
  • 怎样才能防止臭虫在卧室里呢
  • 个税是负数直接工资加上吗
  • 劳务分包费用组成比例
  • 企业出租涉及到的税收
  • 境外代扣代缴企业所得税的计税依据包含企业所得税嘛
  • 管理费用的会计编码
  • vue3.0解决跨域
  • php与jquery
  • 年度确认收入怎么算
  • 温哥华瀑布
  • 最贵的游戏宣传片
  • vue中elementui怎么用
  • chrome浏览器清除数据
  • js获取当前日期的函数
  • 应交城建税怎么算
  • java如何解析json字符串
  • Python web开发基础教程的心得
  • shc命令
  • php新版本特性
  • get命令获取文件夹
  • 长期股权投资成本怎么计算
  • 城市维护建设税是什么意思
  • 水果发票税率是几个点
  • 金税盘证书已冻结怎么解决
  • phpcms使用教程
  • 劳务分包收入交什么税
  • 自产和外购用于赠送
  • 减免增值税记账
  • 大数据sql教程
  • 简易征收的纳税标准
  • 银行保函会计处理
  • 投资利润率怎么看投资好还是不好
  • 印花税算错了地方怎么办
  • 进项税转出补税按多少补税
  • 购买方退货的会计分录怎么写
  • 合伙人工资薪金
  • winxp关闭自动更新方法
  • win10安装固态硬盘打开软件卡
  • centos nis
  • win10每次开机提示硬件设置已更改
  • linux系统怎么增大磁盘io
  • win8系统打不开exe
  • 安卓deprecated
  • shell脚本取n天前的日期
  • python编程求一个数的平方
  • jquery手册手机版
  • android10获取设备id
  • 安卓网络管理类app
  • realm数据库连接
  • 组件中js可以做什么
  • 内蒙古低保信息网
  • 跨县调动工作流程
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设