AOP

AOP 基本概念

OOP是自上而下從controller-service-dao-數(shù)據(jù)庫。

AOP(Aspect-Oriented Programming)面向切面編程。AOP工作原理一句話概括:通過代理模式為目標(biāo)對(duì)象生產(chǎn)代理對(duì)象,并將橫切邏輯插入到目標(biāo)方法執(zhí)行的前后。

術(shù)語

切面(Aspect)

切面是切點(diǎn)和通知的集合,一般單獨(dú)作為一個(gè)類。通知和切點(diǎn)共同定義了關(guān)于切面的全部內(nèi)容。

白話文理解:影響了多個(gè)類的公共行為封裝到一個(gè)可重用模塊。

切點(diǎn)(PointCut)

切點(diǎn)是對(duì)一系列代表同種功能(目的)的切入點(diǎn)(連接點(diǎn))的統(tǒng)稱,切點(diǎn)不是一個(gè)點(diǎn),而是代表某一功能的一系列連接點(diǎn)的集合。通常使用明確的類或者方法名稱,或是利用正則表達(dá)式定義所匹配的類和方法來指定這些切點(diǎn)。

通知(Advice)

通知就是我們要在切點(diǎn)執(zhí)行的操作,就是我們要實(shí)現(xiàn)的目的,是要實(shí)現(xiàn)的功能的代碼實(shí)現(xiàn)。一般通知又稱為增強(qiáng)。

通知有物種類型:

  • Before 在方法被調(diào)用之前調(diào)用

  • After 在方法完成后調(diào)用通知,無論方法是否執(zhí)行成功

  • After-returning 在方法成功執(zhí)行之后調(diào)用通知

  • After-throwing 在方法拋出異常后調(diào)用通知

  • Around 通知了好、包含了被通知的方法,在被通知的方法調(diào)用之前后調(diào)用之后執(zhí)行自定義的行為

這里需要注意Around不是執(zhí)行兩次。如下代碼,而是在pjp.proceed()方法前后的環(huán)繞。


@Around("controllerAspect()")

    public Object around(ProceedingJoinPoint pjp) throws Throwable {

        StopWatch stopWatch = new StopWatch();

        Object result = null;

        Transaction transaction = null;

        String uri = "";

        try {

            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

            ServletContext ctx = request.getSession().getServletContext();

            uri = request.getRequestURI().replace(ctx.getContextPath(), "").toLowerCase();

            uri = uri.substring(uri.lastIndexOf("/") + 1);

            if (uri.trim().matches("^\\d+$")) {

                String numberUri = uri.trim();

                uri = request.getRequestURI().replace(ctx.getContextPath(), "")

                        .replace("/", "").replace(numberUri, "")

                        .toLowerCase();

            }

            logger.info(String.format("controller path uri:%s", uri));

            transaction = Cat.newTransaction(TYPE, uri);

            Cat.logMetric(uri);

            // 執(zhí)行方法

            result = pjp.proceed();

            transaction.setStatus(Transaction.SUCCESS);

            // 默認(rèn)執(zhí)行完方法不報(bào)錯(cuò)就是SUCCESS

            Cat.logEvent(TYPE, uri, Event.SUCCESS, "");

        } catch (Throwable e) {

            logger.error("方法執(zhí)行失敗 controller path=" + uri, e);

            transaction.setStatus(e);

            // 默認(rèn)執(zhí)行完報(bào)錯(cuò)就記失敗

            Cat.logEvent(TYPE, uri, e.getMessage(), "");

            throw e;

        } finally {

            transaction.complete();

        }

        logger.info("controller path={} spent {} seconds", uri, stopWatch.elapsedTime());

        return result;

    }

連接點(diǎn)(JoinPoint)

連接點(diǎn)是在應(yīng)用執(zhí)行過程中能夠插入切面的一個(gè)點(diǎn)。這個(gè)點(diǎn)可以是調(diào)用方法時(shí),拋出異常時(shí),甚至修改一個(gè)字段時(shí)。切面代碼可以利用這些點(diǎn)插入應(yīng)用的正常流程中,并添加新的行為。Spring只支持方法的連接點(diǎn)

織入(Weaving)

織入是把切面應(yīng)用到目標(biāo)對(duì)象并創(chuàng)建新的代理對(duì)象的過程。切面在指定的連接點(diǎn)被織入到目標(biāo)對(duì)象中。在目標(biāo)對(duì)象的生命周期里有多個(gè)點(diǎn)可以進(jìn)行織入。

Spring AOP的切面織入是在運(yùn)行時(shí)被織入,原理是使用了動(dòng)態(tài)代理技術(shù),Spring支持兩種方式生產(chǎn)代理對(duì)象:JDK動(dòng)態(tài)代理和CGLIB,默認(rèn)的策略是如果目標(biāo)類是接口,則使用JDK動(dòng)態(tài)代理技術(shù),否則使用Cglib來生成代理

引入(Introduction)

添加方法或字段到被通知的類。Spring允許引入新的接口到任何被通知的對(duì)象。Spring中要使用Introduction, 可有通過DelegatingIntroductionInterceptor來實(shí)現(xiàn)通知,通過DefaultIntroductionAdvisor來配置Advice和代理類要實(shí)現(xiàn)的接口。

目標(biāo)對(duì)象(Target Object)

包含連接點(diǎn)的對(duì)象。也被稱作被通知或被代理對(duì)象。

AOP代理(AOP Proxy)

AOP框架創(chuàng)建的對(duì)象,包含通知。 在Spring中,AOP代理可以是JDK動(dòng)態(tài)代理或者CGLIB代理。

源碼分析

**1、AOPNamespaceHandler中init是在什么時(shí)候調(diào)用的

2、對(duì)于XML配置AOP加載過程已了解,那么對(duì)于SpringBoot配置AOP加載過程呢。**

**XML配置AOP加載過程。

3、AOP有幾種配置方式,每種配置方式,源碼都是怎么走向。**

1、xml配置 <aop:config>標(biāo)簽使用分析

refresh

-> obtainFreshBeanFactory

-> refreshBeanFactory

-> AbstractRefreshableApplicationContext.loadBeanDefinitions(beanFactory)

-> ...

-> XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource)

-> DefaultBeanDefinitionDocumentReader.parseBeanDefinitions

對(duì)于<aop:config>是自定義的標(biāo)簽不是defaultNamespace(默認(rèn)是bean標(biāo)簽),那么走的是parseCustomElement方法


protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {

if (delegate.isDefaultNamespace(root)) {

NodeList nl = root.getChildNodes();

for (int i = 0; i < nl.getLength(); i++) {

Node node = nl.item(i);

if (node instanceof Element) {

Element ele = (Element) node;

if (delegate.isDefaultNamespace(ele)) {

parseDefaultElement(ele, delegate);

}

else {

delegate.parseCustomElement(ele);

}

}

}

}

else {

delegate.parseCustomElement(root);

}

}


public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {

String namespaceUri = getNamespaceURI(ele);

NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

if (handler == null) {

error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);

return null;

}

return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

}

那么這個(gè)Handler就對(duì)應(yīng)META/spring.handlers文件中。Spring各個(gè)jar包中的spring.handlers都會(huì)生效。

image.png

我們在看下NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);中的resolve方法,此方法拿到namespaceHandler之后會(huì)調(diào)用init方法。


@Override

public NamespaceHandler resolve(String namespaceUri) {

Map<String, Object> handlerMappings = getHandlerMappings();

Object handlerOrClassName = handlerMappings.get(namespaceUri);

if (handlerOrClassName == null) {

return null;

}

else if (handlerOrClassName instanceof NamespaceHandler) {

return (NamespaceHandler) handlerOrClassName;

}

else {

String className = (String) handlerOrClassName;

try {

Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);

if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {

throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +

"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");

}

NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);

namespaceHandler.init();

handlerMappings.put(namespaceUri, namespaceHandler);

return namespaceHandler;

}

catch (ClassNotFoundException ex) {

throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +

namespaceUri + "] not found", ex);

}

catch (LinkageError err) {

throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +

namespaceUri + "]: problem with handler class file or dependent class", err);

}

}

}

然后繼續(xù)看parseCustomElement方法handler.parse方法,<aop:config>標(biāo)簽又交給了ConfigBeanDefinitionParser來解析.

首先findParseForElement獲取parser然后進(jìn)行調(diào)用parse方法。


@Override

public BeanDefinition parse(Element element, ParserContext parserContext) {

return findParserForElement(element, parserContext).parse(element, parserContext);

}

我們來看看ConfigBeanDefinitionParser的parse方法:大致是注冊一個(gè)bean,以及切點(diǎn)、增強(qiáng)、切面的解析(pointcunt\advisor\aspect)


@Override

public BeanDefinition parse(Element element, ParserContext parserContext) {

CompositeComponentDefinition compositeDef =

new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));

parserContext.pushContainingComponent(compositeDef);

configureAutoProxyCreator(parserContext, element);

List<Element> childElts = DomUtils.getChildElements(element);

for (Element elt: childElts) {

String localName = parserContext.getDelegate().getLocalName(elt);

if (POINTCUT.equals(localName)) {

parsePointcut(elt, parserContext);

}

else if (ADVISOR.equals(localName)) {

parseAdvisor(elt, parserContext);

}

else if (ASPECT.equals(localName)) {

parseAspect(elt, parserContext);

}

}

parserContext.popAndRegisterContainingComponent();

return null;

}

configureAutoProxyCreator(parserContext, element);一路跟蹤到如下


public static void registerAspectJAutoProxyCreatorIfNecessary(

ParserContext parserContext, Element sourceElement) {

//注冊一個(gè)AspectJAwareAdvisorAutoProxyCreator,

BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(

parserContext.getRegistry(), parserContext.extractSource(sourceElement));

//解析配置元素,決定代理的模式

useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);

//作為系統(tǒng)組件,把這個(gè)creator這個(gè)bean,放到Spring容器中,讓Spring實(shí)力化,啟動(dòng)這個(gè)Creator

registerComponentIfNecessary(beanDefinition, parserContext);

}

在bean實(shí)例化完成后,會(huì)調(diào)用BeanPostProcessor的postProcessAfterInitialization方法在其父類AbstractAutoProxyCreator中實(shí)現(xiàn),


@Override

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

if (bean != null) {

Object cacheKey = getCacheKey(bean.getClass(), beanName);

if (!this.earlyProxyReferences.contains(cacheKey)) {

return wrapIfNecessary(bean, beanName, cacheKey);

}

}

return bean;

}

跟蹤wrapIfNecessary方法,會(huì)進(jìn)入到createProxy方法


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;

}

if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {

this.advisedBeans.put(cacheKey, Boolean.FALSE);

return bean;

}

// Create proxy if we have advice.

        // 意思就是如果該類有advice則創(chuàng)建proxy,

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

if (specificInterceptors != DO_NOT_PROXY) {

this.advisedBeans.put(cacheKey, Boolean.TRUE);

            // 1.通過方法名也能簡單猜測到,這個(gè)方法就是把bean包裝為proxy的主要方法,

Object proxy = createProxy(

bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

this.proxyTypes.put(cacheKey, proxy.getClass());



            // 2.返回該proxy代替原來的bean

return proxy;

}

this.advisedBeans.put(cacheKey, Boolean.FALSE);

return bean;

}

createProxy方法中最后一句proxyFactory.getProxy會(huì)進(jìn)入到DefaultAopProxyFactory的createAopProxy方法。


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);

if (!proxyFactory.isProxyTargetClass()) {

if (shouldProxyTargetClass(beanClass, beanName)) {

proxyFactory.setProxyTargetClass(true);

}

else {

evaluateProxyInterfaces(beanClass, proxyFactory);

}

}

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

for (Advisor advisor : advisors) {

proxyFactory.addAdvisor(advisor);

}

proxyFactory.setTargetSource(targetSource);

customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);

if (advisorsPreFiltered()) {

proxyFactory.setPreFiltered(true);

}

return proxyFactory.getProxy(getProxyClassLoader());

}


@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.");

}

//如果bean的類是接口或者類是JDK內(nèi)部的代理類,則使用JDK的動(dòng)態(tài)代理類。

if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {

return new JdkDynamicAopProxy(config);

}

//其他情況使用CGLIB來實(shí)現(xiàn)。

return new ObjenesisCglibAopProxy(config);

}

else {

return new JdkDynamicAopProxy(config);

}

}

創(chuàng)建代理類后,其余過程與bean的生命周期基本一致。

2、注解配置 <aop:aspectj-autoproxy>標(biāo)簽使用分析

與aop:config標(biāo)簽大致類似,區(qū)別在于:

1、此標(biāo)簽交給AspectJAutoProxyBeanDefinitionParser去進(jìn)行解析。

2、AspectJAutoProxyBeanDefinitionParser解析時(shí)候注冊的是AnnotationAwareAspectJAutoProxyCreator的bean。

3、SpringBoot配置AOP

SpringBoot項(xiàng)目自動(dòng)化配置是讀取spring-boot-autoconfigure項(xiàng)目中的/META-INF/spring.factories的文件,以及json配置文件


org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\


{

      "name": "spring.aop.auto",

      "type": "java.lang.Boolean",

      "description": "Add @EnableAspectJAutoProxy.",

      "defaultValue": true

    },

我們看下AopAutoConfiguration


@Configuration

//依賴于EnableAspectJAutoProxy與Aspect與Advice

@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })

//spring.aop.auto=true此類才會(huì)進(jìn)行加載

@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)

public class AopAutoConfiguration {

@Configuration

//proxyTargetClass默認(rèn)為false

@EnableAspectJAutoProxy(proxyTargetClass = false)

@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)

public static class JdkDynamicAutoProxyConfiguration {

}

@Configuration

@EnableAspectJAutoProxy(proxyTargetClass = true)

@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)

public static class CglibAutoProxyConfiguration {

}

}

那我們繼續(xù),來看EnableAspectJAutoProxy注解


@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Import(AspectJAutoProxyRegistrar.class)

public @interface EnableAspectJAutoProxy {

/**

* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed

* to standard Java interface-based proxies. The default is {@code false}.

*/

boolean proxyTargetClass() default false;

/**

* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}

* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.

* Off by default, i.e. no guarantees that {@code AopContext} access will work.

* @since 4.3.1

*/

boolean exposeProxy() default false;

}

導(dǎo)入了AspectJAutoProxyRegistrar配置我們來看AspectJAutoProxyRegistrar源碼


class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

/**

* Register, escalate, and configure the AspectJ auto proxy creator based on the value

* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing

* {@code @Configuration} class.

*/

@Override

public void registerBeanDefinitions(

AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy =

AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);

if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {

AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);

}

if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {

AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);

}

}

}

這里是不是很熟悉,相當(dāng)于<aop:aspectj-autoproxy>標(biāo)簽使用,注冊AnnotationAwareAspectJAutoProxyCreator。springboot加載過程就是這樣。

仔細(xì)想想SpringBoot是基于注解的形式,那么肯定是有什么地方調(diào)用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

4、AopNamespaceHandler中init方法


public void init() {

// In 2.0 XSD as well as in 2.1 XSD.

registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());

registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

// Only in 2.0 XSD: moved to context namespace as of 2.1

registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());

}

一二行上面以及介紹過了,對(duì)于scoped-proxy可以理解為作用域代理。Spring中作用域默認(rèn)是singleton.如果想使用其他除了單例模式以外的作用域,則需要添加scoped-proxy標(biāo)簽,默認(rèn)走CGLIB代理。跟蹤代碼到ScopedProxyBeanDefinitionDecorator類中。


public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {

boolean proxyTargetClass = true;

if (node instanceof Element) {

Element ele = (Element) node;

if (ele.hasAttribute(PROXY_TARGET_CLASS)) {

proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS));

}

}

// Register the original bean definition as it will be referenced by the scoped proxy

// and is relevant for tooling (validation, navigation).

BeanDefinitionHolder holder =

ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass);

String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName());

parserContext.getReaderContext().fireComponentRegistered(

new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName));

return holder;

}

再看其createScopedProxy方法


public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,

BeanDefinitionRegistry registry, boolean proxyTargetClass) {

String originalBeanName = definition.getBeanName();

BeanDefinition targetDefinition = definition.getBeanDefinition();

String targetBeanName = getTargetBeanName(originalBeanName);

// Create a scoped proxy definition for the original bean name,

// "hiding" the target bean in an internal target definition.

RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);

proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));

proxyDefinition.setOriginatingBeanDefinition(targetDefinition);

proxyDefinition.setSource(definition.getSource());

proxyDefinition.setRole(targetDefinition.getRole());

proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);

if (proxyTargetClass) {

targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);

// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.

}

else {

proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);

}

// Copy autowire settings from original bean definition.

proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());

proxyDefinition.setPrimary(targetDefinition.isPrimary());

if (targetDefinition instanceof AbstractBeanDefinition) {

proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);

}

// The target bean should be ignored in favor of the scoped proxy.

targetDefinition.setAutowireCandidate(false);

targetDefinition.setPrimary(false);

// Register the target bean as separate bean in the factory.

registry.registerBeanDefinition(targetBeanName, targetDefinition);

// Return the scoped proxy definition as primary bean definition

// (potentially an inner bean).

return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());

}

對(duì)于創(chuàng)建ScopedProxyFactoryBean要看其中的setBeanFactory方法


@Override

public void setBeanFactory(BeanFactory beanFactory) {

if (!(beanFactory instanceof ConfigurableBeanFactory)) {

throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);

}

ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

this.scopedTargetSource.setBeanFactory(beanFactory);

ProxyFactory pf = new ProxyFactory();

pf.copyFrom(this);

pf.setTargetSource(this.scopedTargetSource);

Class<?> beanType = beanFactory.getType(this.targetBeanName);

if (beanType == null) {

throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +

"': Target type could not be determined at the time of proxy creation.");

}

if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {

pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));

}

// Add an introduction that implements only the methods on ScopedObject.

ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());

pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));

// Add the AopInfrastructureBean marker to indicate that the scoped proxy

// itself is not subject to auto-proxying! Only its target bean is.

pf.addInterface(AopInfrastructureBean.class);

this.proxy = pf.getProxy(cbf.getBeanClassLoader());

}

spring-configured不太了解就不多說了,有了解的可以一起交流。

好了寫到這里,喜歡的大家互動(dòng)起來。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 只有光頭才能變強(qiáng) 上一篇已經(jīng)講解了Spring IOC知識(shí)點(diǎn)一網(wǎng)打盡!,這篇主要是講解Spring的AOP模...
    Java3y閱讀 7,028評(píng)論 8 181
  • **** AOP 面向切面編程 底層原理 代理?。。?今天AOP課程1、 Spring 傳統(tǒng) AOP2、 Spri...
    luweicheng24閱讀 1,515評(píng)論 0 1
  • 第五章 Spring AOP 概覽 本章首先是脫離Spring之外講了AOP的基礎(chǔ),其次分析了AOP的兩種類型:...
    劉凝云閱讀 1,146評(píng)論 0 0
  • 我們的程序從編寫到執(zhí)行,單個(gè)模塊一般都是從上到下、垂直、連續(xù)的。AOP是一種“橫切”技術(shù),能夠在合適的地方“攔腰截...
    消失er閱讀 2,098評(píng)論 0 5
  • 今天上午去面試,起個(gè)大早,趕個(gè)晚集。只因?yàn)橛?jì)劃不夠周全,路線不夠熟悉,坐公交必須考慮早高峰堵車的因素,畢竟...
    黑化后的亞瑟閱讀 526評(píng)論 0 6

友情鏈接更多精彩內(nèi)容