Spring 的应用上下文

在spring中,有两种定义上下文做aop拦截的方式。一种是使用Java类做一个父配置。另外一个就是用applicationContext.xml做子配置。
我们在FooConfig.java 中定义两个 testBean,分别为 testBeanX(foo) 和 testBeanY(foo)。
applicationContext.xml 定义了一个 testBeanX(bar)。具体如代码所示:

@AllArgsConstructor
@Slf4j
public class TestBean {
    private String context;

    public void hello() {
        log.info("hello " + context);
    }
}


@Aspect//定义一个切面
@Slf4j
public class FooAspect {
    @AfterReturning("bean(testBean*)") //在你这个testBean*类 成功返回之后执行
    public void printAfter() {
        log.info("after hello()");
    }
}


@Configuration //@Configuration的作用等价于XML配置中的标签,@Bean的作用等价于XML配置中的标签。Spring在解析该类时,会识别出标注@Bean的所有方法,执行并将方法的返回值\注册到IoC容器中。默认情况下,方法名即为Bean的名字。
@EnableAspectJAutoProxy//开启aspectj的支持,对打@aspectj相关注解的类做一个Proxy
public class FooConfig {
    @Bean
    public TestBean testBeanX() {
        return new TestBean("foo");
    }

    @Bean
    public TestBean testBeanY() {
        return new TestBean("foo");
    }

    @Bean
    public FooAspect fooAspect() {
        return new FooAspect();
    }
}
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:aspectj-autoproxy/>

    <bean id="testBeanY" class="geektime.spring.web.context.TestBean">
        <constructor-arg name="context" value="QAQ" />
    </bean>

    <!--<bean id="fooAspect" class="geektime.spring.web.foo.FooAspect" />-->
</beans>

它的委托机制为:在自己的context 中找不到bean,会委托父context 查找该bean。
运行代码如下:

@SpringBootApplication
@Slf4j
public class ContextHierarchyDemoApplication implements ApplicationRunner {

	public static void main(String[] args) {
		SpringApplication.run(ContextHierarchyDemoApplication.class, args);
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		ApplicationContext fooContext = new AnnotationConfigApplicationContext(FooConfig.class);//用这个类加载FooConfig
		ClassPathXmlApplicationContext barContext = new ClassPathXmlApplicationContext(
				new String[] {"applicationContext.xml"}, fooContext);//加载applicationContext.xml,声明fooContext为上级Context
		TestBean bean = fooContext.getBean("testBeanX", TestBean.class); //在父上下文查找 testBeanX,命中直接返回 testBeanX(foo)。
		bean.hello();

		log.info("=============");

		bean = barContext.getBean("testBeanX", TestBean.class);//在子上下文查找 testBeanX,命中直接返回 testBeanX(bar)。
		bean.hello();

		bean = barContext.getBean("testBeanY", TestBean.class);//在子上下文查找 testBeanY,未命中;委托父上下文查找,命中,返回 testBeanY(foo)。
		bean.hello();
	}
}

场景一

在这里插入图片描述
在这里插入图片描述
父上下文开启 @EnableAspectJAutoProxy 的支持
子上下文未开启 <aop: aspectj-autoproxy />
切面 fooAspect 在 FooConfig.java 定义(父上下文增强)

在这里插入图片描述

输出结果:
testBeanX(foo) 和 testBeanY(foo) 均被增强。testBeanX(foo)是子上下文没有找到之后,去父上下文找的
testBeanX(bar) 未被增强。

在父上下文开启了增强,父上下文的 bean 均被增强,而子上下文的 bean 未被增强。

场景二
在这里插入图片描述

父上下文开启 @EnableAspectJAutoProxy 的支持
子上下文开启 <aop: aspectj-autoproxy />
切面 fooAspect 在 applicationContext.xml 定义(子上下文增加)
在这里插入图片描述

输出结果:
testBeanX(foo) 和 testBeanY(foo) 未被增强。
testBeanX(bar) 被增强。

在子上下文开启增强,父的 bean 未被增强,子的 bean 被增强。

从上面两个场景可以看出:
各个 context 相互独立,每个 context 的 aop 增强只对本 context 的 bean 生效。如果想将切面配置成通用的,对父和子上下文的 bean 均支持增强,则:

  1. 切面 fooAspect 定义在父上下文。
  2. 父上下文和子上下文,均要开启 aop 的增加,即 @EnableAspectJAutoProxy 或<aop: aspectj-autoproxy /> 的支持。
发布了59 篇原创文章 · 获赞 6 · 访问量 960

猜你喜欢

转载自blog.csdn.net/weixin_43790623/article/details/103417584