Spring原理学习笔记
学习来源:黑马程序员
学习时间:2023年11月4日
1 容器接口
1.1 BeanFactory和ApplicationContext
最重要的两个接口分别是BeanFactory
和ApplicationContext
。关系如下:
从这个类图我们可以大致看出BeanFactory
和ApplicationContext
的关系,BeanFactory
是ApplicationContext
的基类,BeanFactory所拥有的功能ApplicationContext都拥有,不仅如此,ApplicationContext还拓展了一些功能,它通过实现MessageSource、 ResourceLoader等接口,在BeanFactory简单IOC容器的基础上添加了许多高级容器的特征。
Spring的核心容器是BeanFactory
。
在SpringBoot的引导类中,run方法的返回值就是一个可配置的Spring容器
1 2 3 4 5 6 7 8 9 10
| @SpringBootApplication public class A01Application {
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args); context.getBean("aaa"); } }
|
BeanFactory接口中的方法:
1.2 BeanFactory接口的功能
从1.1节
可以看到BeanFactory提供的方法只有getBean
,而控制反转,依赖注入直到Bean的生命周期的各种功能,是由它的实现类来提供的。
BeanFactory的一个重要的实现类是DefaultListableBeanFactory
,类图如下:
其中DefaultListableBeanFactory
的父类DefaultSingletonBeanRegistry
管理着单例的对象:
1 2 3 4 5 6
| public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256); }
|
准备两个bean,分别为Component1
和Component2
:
1 2 3 4 5 6 7 8 9
| @Component public class Component1 {
}
@Component public class Component2 {
}
|
打印这两个bean的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @SpringBootApplication @ComponentScan public class A01Application {
private static final Logger log = LoggerFactory.getLogger(A01Application.class);
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args); Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects"); singletonObjects.setAccessible(true); ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory); map.entrySet().stream() .filter(e -> e.getKey().startsWith("component")) .forEach(e -> { System.out.println(e.getKey() + "=" + e.getValue()); }); } }
|
打印结果:
1 2
| component1=com.hongyi.apiintegration.spring.Component1@3aa41da1 component2=com.hongyi.apiintegration.spring.Component2@74fab04a
|
1.3 ApplicationContext接口的功能
暂略
2 容器实现
2.1 BeanFactory接口实现
2.1.1 BeanFactoryPostProcessor
DefaultListableBeanFactory
类是BeanFactory
的一个重要的实现类。以此为讲解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public class TestBeanFactory { public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition(); beanFactory.registerBeanDefinition("config", beanDefinition); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); } System.out.println("--------------"); }
@Configuration static class Config { @Bean public Bean1 bean1() { return new Bean1(); }
@Bean public Bean2 bean2() { return new Bean2(); } }
static class Bean1 { private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() { log.debug("构造 Bean1()"); }
@Autowired private Bean2 bean2;
public Bean2 getBean2() { return bean2; } }
static class Bean2 { private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() { log.debug("构造 Bean2()"); } } }
|
打印信息:
发现只有一个config的bean,而没有bean1和bean2的bean。原因在于BeanFactory
并没有提供解析注解的功能,而是需要一些后处理器来完成。
1 2 3 4 5
| AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); }
|
打印结果:
1 2 3 4 5 6 7 8 9
| config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory
|
可以看到容器中多出了几个后处理器的bean,主要分为两类:
- BeanFactory后处理器,
BeanFactoryPostProcessor
,用于解析Component,Bean注解
- Bean后处理器,
BeanPostProcessor
,用于解析Autowired,Resource注解
其中internalConfigurationAnnotationProcessor
后处理器用于解析注解,例如@Configuration
,@Bean
等。
现在执行这些后处理器:
1 2 3 4 5 6 7 8 9
|
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> { beanFactoryPostProcessor.postProcessBeanFactory(beanFactory); }); for (String name : beanFactory.getBeanDefinitionNames()) { System.out.println(name); }
|
打印结果:
1 2 3 4 5 6 7 8
| config org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory bean1 bean2
|
可以看到bean1和bean2的定义被加载进了容器当中。
2.1.2 BeanPostProcessor
现在执行:
1
| System.out.println(beanFactory.getBean(Bean1.class).getBean2());
|
打印结果:
1 2 3 4
| 14:56:08.360 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1' 14:56:08.363 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config' 14:56:08.383 [main] DEBUG com.hongyi.apiintegration.spring.TestBeanFactory$Bean1 - 构造 Bean1() null
|
bean1中注入了bean2,但是打印时却为null,说明@Autowired
注解并未生效。同样需要后处理器来执行,这里后处理器的类型为BeanPostProcessor
。
1 2 3 4
| beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
|
打印结果:
2.1.3 即时加载和延时加载
此外注意到,目前bean对象的产生是延时的(懒加载):当调用到getBean()
时,才调用构造方法,创建出对象。
如果要实现即时加载(饿加载):
1 2 3 4
| beanFactory.preInstantiateSingletons(); System.out.println("--------------"); System.out.println(beanFactory.getBean(Bean1.class).getBean2());
|
打印结果:
可以看到,在执行beanFactory.getBean(Bean1.class).getBean2()
之前,容器就为我们创建好了bean1和bean2的实例对象。
2.1.4 小结
BeanFactory接口不会做的事:
- 不会主动添加和调用BeanFactory后处理器
- 不会主动添加和调用Bean后处理器
- 不会主动初始化单例对象,需要显式调用
preInstantiateSingletons()
- 不会解析
${}
和#{}
2.2 ApplicationContext接口实现
ApplicationContext接口实现类主要有:
ClassPathXmlApplicationContext
类:基于classpath下xml格式的配置文件来创建容器
FileSystemXmlApplicationContext
类:基于磁盘路径下xml格式的配置文件来创建容器
AnnotationConfigApplicationContext
类:基于java配置类来创建
AnnotationConfigServletWebServerApplicationContext
:基于java配置类来创建,用于web环境
2.2.1 ClassPathXmlApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Slf4j public class A02Application { public static void main(String[] args) { testClassPathXmlApplicationContext(); }
private static void testClassPathXmlApplicationContext() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("b01.xml"); for (String name : context.getBeanDefinitionNames()) { System.out.println(name); }
System.out.println(context.getBean(Bean2.class).getBean1()); }
static class Bean1 {
}
static class Bean2 { private Bean1 bean1;
public void setBean1(Bean1 bean1) { this.bean1 = bean1; }
public Bean1 getBean1() { return bean1; } } }
|
在resources
创建配置文件b01.xml
:
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean1" class="com.hongyi.apiintegration.spring.a02.A02Application.Bean1"/>
<bean id="bean2" class="com.hongyi.apiintegration.spring.a02.A02Application.Bean2"> <property name="bean1" ref="bean1"/> </bean>
</beans>
|
打印结果:
2.2.2 FileSystemXmlApplicationContext
略
2.2.3 AnnotationConfigApplicationContext
以Java配置类(以@Configuration
标注)的形式替代了xml
格式的配置文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| @Slf4j public class A02Application { public static void main(String[] args) { testAnnotationConfigApplicationContext(); }
private static void testAnnotationConfigApplicationContext() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) { System.out.println(name); } System.out.println(context.getBean(Bean2.class).getBean1()); }
@Configuration static class Config { @Bean public Bean1 bean1() { return new Bean1(); }
@Bean public Bean2 bean2() { return new Bean2(); } }
static class Bean1 {
}
static class Bean2 { @Autowired private Bean1 bean1;
public void setBean1(Bean1 bean1) { this.bean1 = bean1; }
public Bean1 getBean1() { return bean1; } } }
|
打印结果:
1 2 3 4 5 6 7 8 9
| org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory a02Application.Config bean1 bean2 com.hongyi.apiintegration.spring.a02.A02Application$Bean1@1fb700ee
|
可以看到,容器中有后处理器的定义,还有配置类Config的定义,以及bean1和bean2的定义,依赖注入也成功了。
2.2.4 AnnotationConfigServletWebServerApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @Slf4j public class A02Application { public static void main(String[] args) { testAnnotationConfigServletWebServerApplicationContext(); }
private static void testAnnotationConfigServletWebServerApplicationContext() { AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
@Configuration static class WebConfig { @Bean public ServletWebServerFactory servletWebServerFactory() { return new TomcatServletWebServerFactory(); }
@Bean public DispatcherServlet dispatcherServlet() { return new DispatcherServlet(); }
@Bean public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) { return new DispatcherServletRegistrationBean(dispatcherServlet, "/"); }
@Bean("/hello") public Controller controller1() { return (request, response) -> { response.getWriter().print("Hello World!"); return null; }; } } }
|
访问结果:
3 Bean的生命周期
3.1 四个阶段
按顺序为:
- 实例化(构造)
- 依赖注入
- 初始化
- 销毁
在每个阶段的前后,都可以添加一些Bean后处理器(BeanPostProcessor
)来进行功能增强。
1 2 3 4 5 6 7 8
| @SpringBootApplication public class A03Application { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A03Application.class, args); context.close(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Slf4j @Component public class LifeCycleBean {
public LifeCycleBean() { log.info("构造"); }
@Autowired public void autowire(@Value("${JAVA_HOME}") String home) { log.info("依赖注入:{}", home); }
@PostConstruct public void init() { log.info("初始化"); }
@PreDestroy public void destroy() { log.info("销毁"); } }
|
执行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| @Slf4j @Component public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
@Override public void postProcessBeforeDestruction(Object o, String s) throws BeansException { if (s.equals("lifeCycleBean")) { log.info("<<<<<<<<<< 销毁之前执行, 如@PreDestroy"); } }
@Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) { log.info("<<<<<<<<<< 实例化之前执行, 这里返回的对象会替换原本的bean"); } return null; }
@Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) { log.info("<<<<<<<<<< 实例化之后执行, 这里如果返回false会跳过依赖注入阶段"); } return true; }
@Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) { log.info("<<<<<<<<<< 依赖注入阶段执行, 如@Autowired, @Value, @Resource"); } return pvs; }
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) { log.info("<<<<<<<<<< 初始化之前执行, 这里返回的对象会替换原本的bean, 如@PostConstruct, @ConfigurationProperties"); } return bean; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("lifeCycleBean")) { log.info("<<<<<<<<<< 初始化之后执行, 这里返回的对象会替换原本的bean, 如代理增强"); } return bean; } }
|
执行结果:
3.2 模板方法
模板方法设计模式详见[[Java设计模式学习笔记新#6.1 模板方法模式]]
Bean后处理器采用了模板方法的设计模式。
1 2 3
| public interface BeanPostProcessor { void inject(Object bean); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class MyBeanFactory { private List<BeanPostProcessor> processors = new ArrayList<>();
public Object getBean() { Object bean = new Object(); System.out.println("构造 " + bean); System.out.println("依赖注入 " + bean); for (BeanPostProcessor processor : processors) { processor.inject(bean); } System.out.println("初始化 " + bean); return bean; }
public void addBeanPostProcessors(BeanPostProcessor processor) { processors.add(processor); }
public static void main(String[] args) { MyBeanFactory beanFactory = new MyBeanFactory(); beanFactory.addBeanPostProcessors(bean -> { System.out.println("解析@Autowired"); }); beanFactory.addBeanPostProcessors(bean -> { System.out.println("解析@Resource"); }); Object bean = beanFactory.getBean(); System.out.println(bean); } }
|
打印结果:
1 2 3 4 5
| 构造 java.lang.Object@6433a2 依赖注入 java.lang.Object@6433a2 解析@Autowired 初始化 java.lang.Object@6433a2 java.lang.Object@6433a2
|
4 Bean后处理器
Bean后处理器(BeanPostProcessor
)的作用:为Bean的生命周期的各个阶段(实例化,依赖注入,初始化和销毁)提供扩展。
4.1 常见的Bean后处理器
AutowiredAnnotationBeanPostProcessor
:解析@Autowired
,@Value
注解(涉及依赖注入)
CommonAnnotationBeanPostProcessor
:解析@Resource
,@PostConstruct
,@PreDestroy
注解(涉及依赖注入,初始化和销毁)
ConfigurationPropertiesBindingPostProcessor
:解析@ConfigurationProperties
注解(涉及依赖注入)
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Slf4j public class Bean1 {
private Bean2 bean2;
@Autowired public void setBean2(Bean2 bean2) { log.info("@Autowired生效: {}", bean2); this.bean2 = bean2; }
private Bean3 bean3;
@Resource public void setBean3(Bean3 bean3) { log.info("@Resource生效: {}", bean3); this.bean3 = bean3; }
private String home;
@Autowired public void setHome(@Value("${JAVA_HOME}") String home) { log.info("@Value生效: {}", home); this.home = home; } }
|
1 2 3
| public class Bean2 { }
|
1 2 3 4 5 6 7
| @ConfigurationProperties(prefix = "java") @Data public class Bean4 { private String home;
private String version; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class A04Application {
public static void main(String[] args) { GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1", Bean1.class); context.registerBean("bean2", Bean2.class); context.registerBean("bean3", Bean3.class); context.registerBean("bean4", Bean4.class);
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); context.registerBean(AutowiredAnnotationBeanPostProcessor.class); context.registerBean(CommonAnnotationBeanPostProcessor.class);
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
context.refresh();
System.out.println(context.getBean(Bean4.class));
context.close(); }
}
|
GenericApplicationContext
基本就是对DefaultListableBeanFactory 做了个简易的封装,几乎所有方法都是使用了DefaultListableBeanFactory的方法去实现。
执行结果:
4.2 AutowiredAnnotationBeanPostProcessor流程解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class DigInAutowired { public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerSingleton("bean2", new Bean2()); beanFactory.registerSingleton("bean3", new Bean3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor(); processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1(); System.out.println(bean1); processor.postProcessProperties(null, bean1, "bean1"); System.out.println(bean1); } }
|
打印结果:
可以看到,在未添加bean后处理器时打印bean1,bean1依赖的bean2和home为null,当添加AutowiredAnnotationBeanPostProcessor
类型的后处理器后再次打印,可以看到bean2和home被成功注入,bean3为@Resource
注解,因此未能被注入。
postProcessProperties
方法源码:
1 2 3 4 5
| public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs); }
|
现在使用反射来执行私有方法findAutowiringMetadata
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class DigInAutowired { public static void main(String[] args) throws Throwable { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerSingleton("bean2", new Bean2()); beanFactory.registerSingleton("bean3", new Bean3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor(); processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1(); Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class); findAutowiringMetadata.setAccessible(true); InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null); System.out.println(metadata); metadata.inject(bean1, "bean1", null); System.out.println(bean1); } }
|
invoke
执行后,后处理器将@Autowired注解的属性和方法中的参数封装为InjectionMetadata
,可以看到InjectionMetadata metaData
是一个ArrayList
类型的数组,包含两个元素,即是Bean1中的@Autowired依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private Bean2 bean2;
private String home;
@Autowired public void setBean2(Bean2 bean2) { log.info("@Autowired生效: {}", bean2); this.bean2 = bean2; }
@Autowired public void setHome(@Value("${JAVA_HOME}") String home) { log.info("@Value生效: {}", home); this.home = home; }
|
执行inject
时,容器会从中寻找Bean2
类型和String
类型的bean,完成这些bean的实例化,打印结果为:
那么Spring容器是如何按照类型从容器中来查找Bean1所依赖的bean呢?这涉及到inject
方法的源码,由于源代码实现太过复杂,这里通过反射进行模拟实现:
对于Bean1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Slf4j public class Bean1 {
private Bean2 bean2; @Autowired public void setBean2(Bean2 bean2) { log.info("@Autowired生效: {}", bean2); this.bean2 = bean2; }
@Autowired private Bean3 bean3; }
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class DigInAutowired { public static void main(String[] args) throws Throwable { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerSingleton("bean2", new Bean2()); beanFactory.registerSingleton("bean3", new Bean3());
Field bean3 = Bean1.class.getDeclaredField("bean3"); DependencyDescriptor dd1 = new DependencyDescriptor(bean3, false); Object o1 = beanFactory.doResolveDependency(dd1, null, null, null); System.out.println(o1); Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class); DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), false); Object o2 = beanFactory.doResolveDependency(dd2, null, null, null); System.out.println(o2); } }
|
打印结果:可见被成功注入了。
1 2
| com.hongyi.apiintegration.spring.a04.Bean3@55f3ddb1 com.hongyi.apiintegration.spring.a04.Bean2@2b98378d
|
如果去掉beanFactory.registerSingleton("bean3", new Bean3());
,即不注册Bean3类型的bean,则:
1 2
| null com.hongyi.apiintegration.spring.a04.Bean2@d8355a8
|
再者,如果设置DependencyDescriptor
为true
:
1
| DependencyDescriptor dd1 = new DependencyDescriptor(bean3, true);
|
则结果为:
抛出NoSuchBeanDefinitionException
的异常。
5 BeanFactory后处理器
BeanFactory后处理器(BeanFactoryPostProcessor
)的作用:为BeanFactory做扩展,例如解析注解@ComponentScan
,@Bean
等,将这些被注解标注了的类和方法转换为BeanDefinition
注册到容器中。
5.0 BeanDefinition
BeanDefinition
是定义 Bean 的配置元信息接口,存储Bean的相关信息,主要包括:Bean的属性、是否单例、延迟加载、Bean的名称、构造方法等。
- Spring中每一个被扫描到的bean都会生成一个BeanDefinition
- BeanDefinition的主要作用是为了在只解析一次类的情况下,最大程度的拿到这类的信息。防止重复解析导致效率变低。
该接口派生出 AnnotatedBeanDefinition
接口,以及常用子类 RootBeanDefinition
、GenericBeanDefinition
。
可以使用 BeanDefinitionBuilder
或 new BeanDefinition
实现类构建 BeanDefinition
对象。
5.1 常见的BeanFactory后处理器
ConfigurationClassPostProcessor
:解析@ComponentScan
,@Bean
,@Import
,@ImportResource
MapperScannerConfigurer
:解析@Mapper
,将接口转换为对象
代码示例
1 2 3 4 5
| public class Bean1 { public Bean1() { log.info("我被 Spring 管理了"); } }
|
1 2 3 4 5 6
| @Component public class Bean2 { public Bean2() { log.info("我被 Spring 管理了"); } }
|
1 2 3
| @Mapper public interface Mapper1 { }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Configuration @ComponentScan("com.hongyi.apiintegration.spring.a05.component") public class Config {
@Bean public Bean1 bean1() { return new Bean1(); } @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); return sqlSessionFactoryBean; }
@Bean(initMethod = "init") public DruidDataSource druidDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mysql://localhost:3306/test"); dataSource.setUsername("root"); dataSource.setPassword("12345678"); return dataSource; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Slf4j public class A05Application { public static void main(String[] args) { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("config", Config.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) { System.out.println(name); }
context.close(); } }
|
没有配置BeanFactory后处理器时:
配置后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Slf4j public class A05Application { public static void main(String[] args) { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("config", Config.class);
context.registerBean(ConfigurationClassPostProcessor.class); context.registerBean(MapperScannerConfigurer.class, bd -> { bd.getPropertyValues().add("basePackage", "com.hongyi.apiintegration.spring.a05.mapper"); });
context.refresh();
for (String name : context.getBeanDefinitionNames()) { System.out.println(name); }
context.close(); } }
|
打印的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| config org.springframework.context.annotation.ConfigurationClassPostProcessor org.mybatis.spring.mapper.MapperScannerConfigurer bean2 bean1 sqlSessionFactoryBean druidDataSource mapper1 mapper2 org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory
|
5.2 @ComponentScan流程解析
这里对@ComponentScan
注解的流程进行模拟实现,并抽取成一个自定义的BeanFactory后处理器。
- bean的准备:位于包
com.hongyi.apiintegration.spring.a05.component
下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Component public class Bean2 { public Bean2() { log.info("我被 Spring 管理了"); } }
@Controller @Slf4j public class Bean3 { public Bean3() { log.info("我被 Spring 管理了"); } }
public class Bean4 { public Bean4() { log.info("我被 Spring 管理了"); } }
|
步骤:
- 查看配置类是否有
@ComponentScan
注解
- 获取
@ComponentScan
的value
属性(可能有多个),即扫描的包com.hongyi.apiintegration.spring.a05.component
,遍历每个包
- 遍历该包下的所有类,查看每一个类是否有
@Component
注解或者派生注解修饰
- 如果有修饰,则根据该类的信息构造
BeanDefinition
,然后注册到Bean工厂中,完成注解扫描的功能
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| @Slf4j public class A05Application { public static void main(String[] args) throws IOException { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("config", Config.class); ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class); if (componentScan != null) { for (String p : componentScan.basePackages()) { System.out.println(p); String path = "classpath*:" + p.replace(".", "/") + "/**/*.class"; System.out.println(path); Resource[] resources = context.getResources(path); CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator(); for (Resource resource : resources) { MetadataReader reader = factory.getMetadataReader(resource); if (reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()) || reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName())) { DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory(); AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder .genericBeanDefinition(reader.getClassMetadata().getClassName()) .getBeanDefinition(); String beanName = generator.generateBeanName(beanDefinition, beanFactory); beanFactory.registerBeanDefinition(beanName, beanDefinition); } } } }
context.refresh();
for (String name : context.getBeanDefinitionNames()) { System.out.println(name); }
context.close(); } }
|
打印结果:
现在封装成ComponentScanPostProcessor
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class ComponentScanPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { try { ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class); if (componentScan != null) { for (String p : componentScan.basePackages()) { System.out.println(p); String path = "classpath*:" + p.replace(".", "/") + "/**/*.class"; System.out.println(path); CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path); AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator(); for (Resource resource : resources) { MetadataReader reader = factory.getMetadataReader(resource); if (reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()) || reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName())) { AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder .genericBeanDefinition(reader.getClassMetadata().getClassName()) .getBeanDefinition(); if (configurableListableBeanFactory instanceof DefaultListableBeanFactory) { DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory; String beanName = generator.generateBeanName(beanDefinition, beanFactory); beanFactory.registerBeanDefinition(beanName, beanDefinition); } } } } } } catch (IOException e) { e.printStackTrace(); } } }
|
将该后处理器注册到容器中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Slf4j public class A05Application { public static void main(String[] args) throws IOException { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("config", Config.class); context.registerBean(ComponentScanPostProcessor.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) { System.out.println(name); }
context.close(); } }
|
打印结果:
5.3 @Bean流程解析
对配置类Config
中每一个被标注了@Bean
的方法进行遍历,然后构造BeanDefinition
注册到容器中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class AtBeanPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { try { CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/hongyi/apiintegration/spring/a05/Config.class")); Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName()); for (MethodMetadata method : methods) { System.out.println(method); Map<String, Object> annotationAttributes = method.getAnnotationAttributes(Bean.class.getName()); String initMethod = (String) annotationAttributes.get("initMethod"); BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); builder.setFactoryMethodOnBean(method.getMethodName(), "config"); builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); if (initMethod.length() > 0) { builder.setInitMethodName(initMethod); } AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); if (configurableListableBeanFactory instanceof DefaultListableBeanFactory) { DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory; beanFactory.registerBeanDefinition(method.getMethodName(), beanDefinition); }
} } catch (IOException e) { e.printStackTrace(); } } }
|
将这个后处理器注册到容器中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Slf4j public class A05Application { public static void main(String[] args) throws IOException { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("config", Config.class); context.registerBean(ComponentScanPostProcessor.class); context.registerBean(AtBeanPostProcessor.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) { System.out.println(name); }
context.close(); } }
|
执行结果:
5.4 @Mapper流程解析
暂略
6 Aware接口
Aware
接口提供了一种内置的注入手段,可以注入BeanFactory
,ApplicationContext
InitializingBean
接口提供了一种内置的初始化手段
- 内置的注入和初始化不受扩展功能的影响,总是会被执行
6.1 常见接口
BeanNameAware
接口:注入bean的名字
BeanFactoryAware
接口:注入BeanFactory容器
ApplicationContextAware
接口:注入ApplicationContext容器
EmbeddedValueResolverAware
接口:解析${}
和#{}
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Slf4j public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean { @Override public void setBeanName(String name) { log.info("当前的bean" + this + " 名字是: " + name); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("当前的bean" + this + " 容器是: " + applicationContext); } @Override public void afterPropertiesSet() { log.info("当前的bean" + this + " 初始化"); } }
|
测试:
1 2 3 4 5 6 7 8
| public class A06Application { public static void main(String[] args) { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("myBean", MyBean.class); context.refresh(); context.close(); } }
|
执行结果:
这些接口与@Autowired
和@PostConstruct
的不同:
@Autowired
和@PostConstruct
需要使用BeanPostProcessor
后处理器,属于扩展功能
Aware
接口属于内置功能,在某些情况下,扩展功能会失效,而内置功能不会失效
代码示例
MyBean
增加代码:
1 2 3 4 5 6 7 8 9
| @Autowired public void aaa(ApplicationContext applicationContext) { log.info("当前的bean" + this + " 使用@Autowired注入的容器是: " + applicationContext); }
@PostConstruct public void init() { log.info("当前的bean" + this + " 使用@PostConstruct初始化"); }
|
运行后和上面的结果一样,说明@Autowired
和@PostConstruct
注解失效。
解决办法:为容器注册相应的Bean后处理器
1 2
| context.registerBean(AutowiredAnnotationBeanPostProcessor.class); context.registerBean(CommonAnnotationBeanPostProcessor.class);
|
执行结果:
6.2 @Autowired失效
代码示例
在配置类中配置一个BeanFactoryPostProcessor的Bean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Configuration public class MyConfig1 {
@Autowired public void setApplicationContext(ApplicationContext applicationContext) { log.info("注入ApplicationContext: " + applicationContext); }
@PostConstruct public void init() { log.info("初始化"); }
@Bean public BeanFactoryPostProcessor processor1() { return beanFactory -> { log.info("执行processor1"); }; }
}
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class A06Application { public static void main(String[] args) { GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("myConfig1", MyConfig1.class); context.registerBean(AutowiredAnnotationBeanPostProcessor.class); context.registerBean(CommonAnnotationBeanPostProcessor.class); context.registerBean(ConfigurationClassPostProcessor.class);
context.refresh(); context.close(); } }
|
执行结果:
发现ApplicationContext
未能注入,并且@PostConstruct
注解的初始化方法也未能执行。
原因分析
配置类中不包含BeanFactoryPostProcessor
时的情况:
当配置类包含BeanFactoryPostProcessor
时,因此要创建BeanFactoryPostProcessor
必须提前创建Java配置类,而此时的BeanPostProcessor
尚未准备好,导致@Autowired
和@PostConstruct
失效:
修改代码
实现Aware
接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Slf4j @Configuration public class MyConfig2 implements InitializingBean, ApplicationContextAware {
@Override public void afterPropertiesSet() throws Exception { log.info("初始化"); }
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("注入ApplicationContext: " + applicationContext); }
@Bean public BeanFactoryPostProcessor processor1() { return beanFactory -> { log.info("执行processor1"); }; } }
|
现在能够成功注入。
7 初始化和销毁
7.1 初始化
初始化的手段有三种:
- 使用
@PostConstruct
注解
- 实现
InitializingBean
接口,并重写
- 指定
@Bean
的initMethod
属性
执行顺序:由上到下
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Slf4j public class Bean1 implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { log.info("InitializingBean初始化"); }
@PostConstruct public void init2() { log.info("@PostConstruct初始化"); }
public void init3() { log.info("@Bean的initMethod初始化"); } }
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @SpringBootApplication public class A07Application {
@Bean(initMethod = "init3") public Bean1 bean1() { return new Bean1(); }
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A07Application.class, args); context.close(); }
}
|
执行结果:
7.2 销毁
销毁的手段有三种:
- 使用
@PreDestroy
注解
- 实现
Disposable
接口,并重写
- 指定
@Bean
的destroyMethod
属性
代码略
8 Scope作用域
bean的Scope
有五种:
Singleton
Prototype
Request
Session
Application
8.1 域演示
现在演示后面三个域。
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Slf4j @Scope("application") @Component public class BeanForApplication { @PreDestroy public void destroy() { log.info("destroy"); } }
@Slf4j @Scope("request") @Component public class BeanForRequest { @PreDestroy public void destroy() { log.info("destroy"); } }
@Slf4j @Scope("session") @Component public class BeanForSession { @PreDestroy public void destroy() { log.info("destroy"); } }
|
控制器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @RestController public class MyController { @Lazy @Autowired private BeanForSession beanForSession;
@Lazy @Autowired private BeanForApplication beanForApplication;
@Lazy @Autowired private BeanForRequest beanForRequest;
@GetMapping(value = "/test", produces = "text/html") public String test(HttpServletRequest request, HttpServletResponse response) { ServletContext sc = request.getServletContext(); return "<ul>" + "<li>" + "request scope:" + beanForRequest + "</li>" + "<li>" + "session scope:" + beanForSession + "</li>" + "<li>" + "application scope:" + beanForApplication + "</li>" + "</ul>"; } }
|
发送请求后,返回:
1 2 3
| request scope:com.hongyi.apiintegration.spring.a08.BeanForRequest@5e949f21 session scope:com.hongyi.apiintegration.spring.a08.BeanForSession@9eb8728 application scope:com.hongyi.apiintegration.spring.a08.BeanForApplication@52f10fb9
|
再次发送请求:
1 2 3
| request scope:com.hongyi.apiintegration.spring.a08.BeanForRequest@3f3a62a3 session scope:com.hongyi.apiintegration.spring.a08.BeanForSession@9eb8728 application scope:com.hongyi.apiintegration.spring.a08.BeanForApplication@52f10fb9
|
发现只是request域的对象发生了变化,此外:
1 2 3
| 2023-11-17 14:25:07.754 c.h.a.spring.a08.BeanForRequest : destroy 2023-11-17 14:25:12.714 c.h.a.spring.a08.BeanForRequest : destroy 2023-11-17 14:25:20.673 c.h.a.spring.a08.BeanForRequest : destroy
|
可以看到当请求完成后,request域的对象会被销毁,而session域和application域的对象不会被销毁。
session域对象的存活时间默认为30min
,可以设置:
1 2 3 4 5
| server: port: 80 servlet: session: timeout: 10s
|
8.2 @Scope失效
当一个单例对象注入其他scope(除了单例之外)的对象时,会发生后者scope失效的问题。
演示
1 2 3 4 5 6 7 8 9
| @Component public class E { @Autowired private F f;
public F getF() { return f; } }
|
1 2 3 4 5
| @Scope("prototype") @Component public class F {
}
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12
| @Slf4j @ComponentScan("com.hongyi.apiintegration.spring.a09") public class A09Application { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class); E e = context.getBean(E.class); System.out.println(e.getF()); System.out.println(e.getF()); System.out.println(e.getF()); context.close(); } }
|
执行结果:
1 2 3
| com.hongyi.apiintegration.spring.a09.F@5e0e82ae com.hongyi.apiintegration.spring.a09.F@5e0e82ae com.hongyi.apiintegration.spring.a09.F@5e0e82ae 发现是同一个对象
|
失效原因
对于单例对象,依赖注入只执行一次,E
用的始终是第一次依赖注入的F
。
解决方法
- 方法1:依赖注入时使用
@Lazy
注解生成一个代理对象,再由代理对象来调用F的方法
1 2 3
| @Lazy @Autowired private F f;
|
1 2 3 4
| System.out.println(e.getF().getClass()); System.out.println(e.getF()); System.out.println(e.getF()); System.out.println(e.getF());
|
执行结果:
1 2 3 4
| class com.hongyi.apiintegration.spring.a09.F$$EnhancerBySpringCGLIB$$3be3693d // 被CGLIB代理增强的F的子类代理 com.hongyi.apiintegration.spring.a09.F@2b91004a com.hongyi.apiintegration.spring.a09.F@2fb3536e com.hongyi.apiintegration.spring.a09.F@35aea049
|
1 2 3 4 5
| @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) @Component public class F {
}
|
1 2 3 4 5 6
| @Autowired private ObjectFactory<F> f;
public F getF() { return f.getObject(); }
|
1 2 3 4 5 6
| @Autowired private ApplicationContext context;
public F getF() { return context.getBean(F.class); }
|
9 AOP实现
9.1 AspectJ
AspectJ
编译器能够实现AOP的功能,原理在于它能在编译阶段将class
文件进行修改(增强)。
需要在pom
中引入AspectJ
的依赖和插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> </dependency>
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.14.0</version> <configuration> <complianceLevel>1.8</complianceLevel> <source>8</source> <target>8</target> <showWeaveInfo>true</showWeaveInfo> <verbose>true</verbose> <Xlint>ignore</Xlint> <encoding>UTF-8</encoding> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>test-compile</goal> </goals> </execution> </executions> </plugin>
|
1 2 3 4 5 6 7 8 9 10
| @Service public class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
public void foo() { log.info("foo()"); } }
|
1 2 3 4 5 6 7 8 9 10 11
| @Aspect public class MyAspect {
private static final Logger log = LoggerFactory.getLogger(MyAspect.class); @Before("execution(* com.hongyi.aspectj_01.service.MyService.foo())") public void before() { log.info("before()"); } }
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @SpringBootApplication public class Aspectj01Application {
private static final Logger log = LoggerFactory.getLogger(Aspectj01Application.class);
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(Aspectj01Application.class, args); MyService service = context.getBean(MyService.class); log.info("service class: {}", service.getClass()); service.foo(); context.close(); }
}
|
打印结果:
查看反编译后的MyService
的class
文件,发现源码中多了一行由AspectJ
添加的方法:
1 2 3 4 5 6 7 8 9 10 11 12
| @Service public class MyService { private static final Logger log = LoggerFactory.getLogger(MyService.class);
public MyService() { }
public void foo() { MyAspect.aspectOf().before(); log.info("foo()"); } }
|
切面类并没有被容器管理,将容器相关的测试代码删除后再进行测试:
1 2 3 4 5 6
| public class Aspectj01Application { private static final Logger log = LoggerFactory.getLogger(Aspectj01Application.class); public static void main(String[] args) { new MyService().foo(); } }
|
打印结果:
依然能够进行方法增强。
9.2 Agent
在类加载阶段修改代码来增强方法。
9.3 Proxy
9.3.1 JDK动态代理
可参考[[Java设计模式学习笔记新#5.1.4 JDK动态代理]]
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class JdkProxyDemo { interface Foo { void foo(); }
static class Target implements Foo { @Override public void foo() { System.out.println("target foo"); } }
public static void main(String[] args) { Target target = new Target(); Foo proxyInstance = (Foo) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args1) -> { System.out.println("before..."); Object result = method.invoke(target, args1); System.out.println("after..."); return result; } ); proxyInstance.foo(); } }
|
执行结果:
1 2 3
| before... target foo after...
|
目标类和代理类是平级的兄弟关系,相同点在于他们都实现了目标类的接口。
9.3.2 CGLIB动态代理
参见[[Java设计模式学习笔记新#5.1.5 CGLIB动态代理]]
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class CglibProxyDemo { static class Target { public void foo() { System.out.println("target foo"); } }
public static void main(String[] args) { Target target = new Target(); Target proxyInstance = (Target) Enhancer.create(Target.class, (MethodInterceptor) (proxy, method, args1, methodProxy) -> { System.out.println("before..."); Object result = method.invoke(target, args1); System.out.println("after..."); return result; }); proxyInstance.foo(); } }
|
目标类和代理类是父子关系。
- 如果目标类是
final
,则不能使用cglib
来代理。
- 如果目标类的方法是
final
,也会代理失败(因为代理类是通过重写父类的方法来进行增强的)。
此外:methodProxy
可以避免反射来调用目标的方法
1 2 3 4 5 6 7 8
|
Object result = methodProxy.invoke(target, args1);
Object result = methodProxy.invokeSuper(proxy, args1);
|
9.4 JDK动态代理原理
下面模拟实现JDK的动态代理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class A13 { interface Foo { void foo(); int bar(); }
static class Target implements Foo { @Override public void foo() { System.out.println("target foo"); }
@Override public int bar() { System.out.println("target bar"); return 100; } } interface InvocationHandler { Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } public static void main(String[] args) { Foo proxy0 = new $Proxy0((proxy, method, args1) -> { System.out.println("before..."); return method.invoke(new Target(), args1); }); proxy0.foo(); proxy0.bar(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class $Proxy0 implements Foo {
private final InvocationHandler h;
public $Proxy0(InvocationHandler h) { this.h = h; }
@Override public void foo() { try { h.invoke(this, foo, new Object[0]); } catch (RuntimeException | Error e) { throw e; } catch (Throwable e) { throw new UndeclaredThrowableException(e); } }
@Override public int bar() { try { Object result = h.invoke(this, bar, new Object[0]); return (int) result; } catch (RuntimeException | Error e) { throw e; } catch (Throwable e) { throw new UndeclaredThrowableException(e); } }
static Method foo; static Method bar;
static { try { foo = Foo.class.getMethod("foo"); bar = Foo.class.getMethod("bar"); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } }
|
执行结果:
1 2 3 4
| before... target foo before... target bar
|
9.5 CGLIB动态代理原理
9.5.1 模拟实现
下面模拟实现CGLIB的动态代理。
MethodInterceptor
接口:和JDK动态代理的InvocationHandler类似
1 2 3
| public interface MethodInterceptor { Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Target { public void save() { System.out.println("save()"); }
public void save(int i) { System.out.println("save(int)"); }
public void save(long j) { System.out.println("save(long)"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class Proxy extends Target{ private final MethodInterceptor methodInterceptor;
public Proxy(MethodInterceptor methodInterceptor) { this.methodInterceptor = methodInterceptor; }
static Method save0; static Method save1; static Method save2; static { try { save0 = Target.class.getMethod("save"); save1 = Target.class.getMethod("save", int.class); save2 = Target.class.getMethod("save", long.class); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } }
@Override public void save() { try { methodInterceptor.intercept(this, save0, new Object[0], null); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } }
@Override public void save(int i) { try { methodInterceptor.intercept(this, save1, new Object[]{i}, null); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } }
@Override public void save(long j) { try { methodInterceptor.intercept(this, save2, new Object[]{j}, null); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } }
|
1 2 3 4 5 6 7 8 9 10 11
| public class A14 { public static void main(String[] args) { Proxy proxy = new Proxy((o, method, args1, methodProxy) -> { System.out.println("before..."); return method.invoke(new Target(), args1); }); proxy.save(); proxy.save(1); proxy.save(1L); } }
|
运行结果:
1 2 3 4 5 6
| before... save() before... save(int) before... save(long)
|
9.5.2 MethodProxy
CGLIB的MethodInterceptor
的方法intercept
相比于JDK的InvocationHandler
接口的invoke
方法参数多了一个MethodProxy
,它能避免使用反射来执行目标对象的方法。
9.6 Spring选择代理
9.6.1 Spring的代理选择规则
两个切面的概念:
aspect
:该切面是通知(advice
)和切点(pointcut
)的集合,例如通知1和切点1,通知2和切点2等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Aspect public class MyAspect { @Before("execution(* foo())") public void before() { System.out.println("前置增强"); } @After("execution(* foo())") public void after() { System.out.println("后置增强"); } }
|
advisor
:该切面是更细粒度的切面,只包含一个通知和切点。
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| public class A15 { public static void main(String[] args) { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("execution(* foo())");
MethodInterceptor advice = invocation -> { System.out.println("before..."); Object result = invocation.proceed(); System.out.println("after..."); return result; };
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
Target2 target = new Target2(); ProxyFactory factory = new ProxyFactory(); factory.setTarget(target); factory.addAdvisor(advisor); factory.setInterfaces(target.getClass().getInterfaces()); Target2 proxy = (Target2) factory.getProxy(); System.out.println(proxy.getClass()); proxy.foo(); proxy.bar(); }
interface I1 { void foo();
void bar(); } static class Target1 implements I1 { @Override public void foo() { System.out.println("target1 foo"); }
@Override public void bar() { System.out.println("target1 bar"); } } static class Target2 {
public void foo() { System.out.println("target2 foo"); }
public void bar() { System.out.println("target2 bar"); } } }
|
执行结果:
1 2 3 4 5
| com.hongyi.apiintegration.spring.a15.A15$Target2$$EnhancerBySpringCGLIB$$e9831691 // CGLIB代理 before... target2 foo after... target2 bar
|
1 2 3 4 5 6 7 8 9 10
| Target1 target = new Target1(); ProxyFactory factory = new ProxyFactory(); factory.setTarget(target); factory.addAdvisor(advisor);
factory.setInterfaces(target.getClass().getInterfaces()); I1 proxy = (I1) factory.getProxy(); System.out.println(proxy.getClass()); proxy.foo(); proxy.bar();
|
打印结果:
1 2 3 4 5
| class com.hongyi.apiintegration.spring.a15.$Proxy0 // JDK代理 before... target1 foo after... target1 bar
|
1 2 3 4 5 6 7 8 9 10 11
| Target1 target = new Target1(); ProxyFactory factory = new ProxyFactory(); factory.setTarget(target); factory.addAdvisor(advisor); factory.setInterfaces(target.getClass().getInterfaces());
factory.setProxyTargetClass(true); I1 proxy = (I1) factory.getProxy(); System.out.println(proxy.getClass()); proxy.foo(); proxy.bar();
|
打印结果:
1 2 3 4 5
| classcom.hongyi.apiintegration.spring.a15.A15$Target1$$EnhancerBySpringCGLIB$$8ccfe76e before... target1 foo after... target1 bar
|
总结
Spring创建代理的选择规则:
proxyTargetClass=false
:目标实现了接口,则Spring采用JDK来创建代理
proxyTargetClass=false
:目标没有实现接口,则Spring采用CGLIB来创建代理
proxyTargetClass=true
:Spring采用CGLIB来创建代理
9.6.2 切点匹配
SpringAOP通过切点表达式来进行切点的匹配。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class A16 { public static void main(String[] args) throws NoSuchMethodException { AspectJExpressionPointcut pt1 = new AspectJExpressionPointcut(); pt1.setExpression("execution(* bar())"); System.out.println(pt1.matches(T1.class.getMethod("foo"), T1.class)); System.out.println(pt1.matches(T1.class.getMethod("bar"), T1.class));
AspectJExpressionPointcut pt2 = new AspectJExpressionPointcut(); pt2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)"); System.out.println(pt2.matches(T1.class.getMethod("foo"), T1.class)); System.out.println(pt2.matches(T1.class.getMethod("bar"), T1.class)); }
static class T1 { @Transactional public void foo() {
}
public void bar() {
} } }
|
但这种方式不能匹配在类上或接口上的注解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public class A16 { public static void main(String[] args) throws NoSuchMethodException { StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut() { @Override public boolean matches(Method method, Class<?> targetClass) { MergedAnnotations annotations = MergedAnnotations.from(method); if (annotations.isPresent(Transactional.class)) { return true; } annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY); return annotations.isPresent(Transactional.class); } }; System.out.println(pt3.matches(T1.class.getMethod("foo"), T1.class)); System.out.println(pt3.matches(T1.class.getMethod("bar"), T1.class)); System.out.println(pt3.matches(T2.class.getMethod("foo"), T2.class)); System.out.println(pt3.matches(T3.class.getMethod("foo"), T3.class)); }
static class T1 { @Transactional public void foo() {
}
public void bar() {
} }
@Transactional static class T2 { public void foo() {
} }
@Transactional interface I3 { void foo(); }
static class T3 implements I3 { @Override public void foo() {
} } }
|
总结:底层切点的实现调用了aspectj
的匹配方法
9.6.3 两种切面
底层实现中需要将高级切面转换为低级切面。
切面的识别和转换依赖于AnnotationAwareAspectJAutoProxyCreator
。它是一个Bean后处理器,在依赖注入之前和初始化之后执行。
作用:
该类有两个重要方法:
findEligibleAdvisors
:找到有资格的Advisors(切面)
- 一部分切面是低级的,可以自己编写
- 一部分切面是高级的,需要对
@Aspect
进行解析后获得
wrapIfNecessary
:内部调用了findEligibleAdvisors
,只要返回集合不为空,就表示需要创建代理
9.6.4 代理对象的创建时机