spring应用上下文层级关系
applicationContext中包含了业务的pojos对象还有配置的信息,spring将这些信息通过context的形式结合了在一起,由它来形成一个完整的系统,spring application context管理了所有组件的生命周期。
应用上下文一般分成两大块:一块是servlet WebApplicationContext:里面放的是与Spring mvc相关的一些bean。早期在配置componentScan会加上一些filter只要扫描controller注解的一些bean就好,在web.xml中配置其它配置文件的加载。
servlet WebApplicationContext里面放controller,root WebApplicationContext里面放service和repository。
servlet WebApplicationContext继承了root WebApplicationContext,在servlet里面找不到对应的bean时会在root里面找。
在日常开发中使用一些中间件时,中间件是通过aop来对方法进行增强从而来实现功能的。我们在配置中间件时要注意配置application上下文关系,注意是需要增强servlet WebApplication还是root WebApplication。下面我们用一个demo来理解spring上下文层级关系
我们使用springboot构建一个demo,分别用注解和xml配置的方式来创建两个applicationContext对象,其中一个上下文继承另外一个上下文,通过分别开启父类子类的aop代理来观察现象
需要增强的类
@AllArgsConstructor
@Slf4j
public class TestBean {
private String name;
public void print(){
log.info("hello"+name);
}
}
1、注解方式配置切面
@Slf4j
@Aspect //定义为切面
public class TestAspect {
@AfterReturning("bean(testBean*)") //定义通知及切入点,aop增强效果是在方法执行后增加日志“after hello”
public void after(){
log.info("after hello");
}
}
2、xml配置上下文
<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/> //开启aop代理
-->
<bean id="testBeanX" class="com.changli.applicationContext.TestBean">
<constructor-arg name="name" value="testBeanX"/>
</bean>
<!--
<bean id="testAspect" class="com.changli.applicationContext.parent.TestAspect"/> //注入切面bean
-->
</beans>
3、通过注解配置上下文
@Configuration //定义为配置类
@EnableAspectJAutoProxy //开启aop代理
public class ParentConfig {
@Bean
public TestBean testBeanX(){
return new TestBean("testBeanX");
}
@Bean
public TestBean testBeanY(){
return new TestBean("testBeanY");
}
@Bean
public TestAspect testAspect(){
return new TestAspect();
}
}
4、主程序
@SpringBootApplication
@Slf4j
public class ApplicationContextApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ApplicationContextApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
ApplicationContext parent = new AnnotationConfigApplicationContext(ParentConfig.class); //加载注解配置的上下文
ClassPathXmlApplicationContext child =new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"},parent); //加载xml配置的上下文并继承注解配置的上下文
TestBean beanFromParent = parent.getBean("testBeanX",TestBean.class);
beanFromParent.print();
log.info("================================================");
TestBean beanFromChild =child.getBean("testBeanX",TestBean.class);
beanFromChild.print();
beanFromChild =child.getBean("testBeanY",TestBean.class);
beanFromChild.print();
}
}
运行结果
程序运行结果如上图,从父类上下文中拿出的testBeanX的方法得到了增强,从子类上下文中拿出的testBeanX,由于子类中也有定义testBeanX所以不会从父类拿,子类中没有对方法进行增强,所有没有打印after hello。子类中没有定义testBeanY,所以只能从父类中拿,父类中的方法增强了的,所以打印了after hello。
同理,你还可以将父类上下文的aop代理去掉,在子类中添加。试一试看看结果是否符合你的预期呢
demo的git地址
https://github.com/struggle1to1win/applicationContext.git
注:看丁雪峰老师教学视频后的学习笔记,侵删