学习中!!!!!!!!!!!!!!!
Spring笔记
3-8
BeanFactory && ApplicationContext
BeanFactory
首先,从SpringBoot的主启动类来看
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
}
}
在IDEA中将光标放到ConfigurableApplication上,ctrl + alt + u。 可查看该类的相关类图如下:
可以看到ConfigurableApplication、ApplicationContext、BeanFactory。从图中可以看出ApplicationContext间接实现了BeanFactory而ConfigurableApplication实现ApplicationContext。也就是更核心的其实就是BeanFactory
使用Debug对ConfigableApplication的实例进行查看,可以看到示例中包含beanFactory对象
然而单纯的看BeanFactory,其名下并没有太多的方法
最主要的其实是BeanFactory的实现类DefaultListableBeanFactory。其继承、实现的接口、类的情况如下
虽然BeanFactory表面上看着比较简单,但是实际上控制反转、依赖注入、Bean的生命周期等功能,都是由他的实现类来提供的
以DefaultListableBeanFactory间接继承的父类DefauleSingletonBeanRegistry为例,获取对应的单例bean
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
System.out.println(run);
//因为singletonObjects是私有的,所以通过反射,获取DefaultSingletonBeanRegistry类中的名为singletonObjects的属性。
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
//设置私有属性在类外面允许被访问
singletonObjects.setAccessible(true);
//获取当前Springboot实例的Bean Factory
ConfigurableListableBeanFactory beanFactory = run.getBeanFactory();
//根据beanFactory对象获取其对应的单例Bean的Map 键表示Bean的名称,值表示Bean的实例
Map<String,Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
//输出key value
map.forEach((k,v)->System.out.println(k + "=" + v));
}
可以使用@commpent @service等注解来注入对应的类,这些注解都会被Spring Boot识别,前提是放到类上,不要放到接口上,接口也不能实例化
ApplicationContext
MessageSource: getMessage().主要是读取对应的properties文件,进行一个语言的转化
ResourcePatternResolver:getResources() 读取对应通配符路径下的文件,参数例classpath:application.properties
,通配符如:classpath: \ filed:
等
EnvironmentCapable:getEnvironment() 主要是获取环境中的键值相关的信息,如环境变量、yaml文件中的某个键的值,例run.getEnvironment().getProperty("server.port")
ApplicationEventPublisher:publishEvent()事件监听,主要可以用来解耦合,可以通过@EventListener注解来监听
3-9
BeanFactory && ApplicationContext
BeanFactory的实现
首先,如下测试代码
public class BeanFactoryTest {
public static void main(String[] args) {
//创建一个factory实例对象,当前的factory中并没有任何的Bean
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//Bean的定义(class、scope、初始化、销毁等),定义一些Bean放入到factory中
//BeanDefinitionBuilder是一个工具类,用于构架一个BeanDefinition对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).getBeanDefinition();
//将定义的Bean加入到factory中,需要为其命名
factory.registerBeanDefinition("config",beanDefinition);
//输出已经注入的Bean
Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);
}
@Configuration
static class Config{
public Bean1 bean1(){
return new Bean1();
}
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(Bean1.class);
public Bean2(){
log.debug("bean2");
}
}
}
执行该代码后发现,只有我们手动定义的Config被注入到beanfactory中。@Configuration注解、@Bean注解并没有起到作用。由此可以看出,注解标注的类等,并不是有beanfactory直接注入的,而是由别的类来完成
修改后:
public static void main(String[] args) {
//创建一个factory实例对象,当前的factory中并没有任何的Bean
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//Bean的定义(class、scope、初始化、销毁等),定义一些Bean放入到factory中
//BeanDefinitionBuilder是一个工具类,用于构架一个BeanDefinition对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).getBeanDefinition();
//将定义的Bean加入到factory中,需要为其命名
factory.registerBeanDefinition("config",beanDefinition);
//注册注解处理器,注册Spring上下问的注解,向beanFactory中注册所需的注解处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(factory);
/**
* BeanFactoryPostProcessor 是一种特殊的 Bean,
* 用于在 Spring 容器实例化所有其他 Bean 之前,对 BeanFactory 进行修改。
* 这些修改可能包括添加、修改或删除 Bean 的属性,修改 Bean 的定义等
*/
//获取BeanFactoryPostProcessor相关的已经注入的Bean,@Configuration、@Autowired、@PostConstruct、@PreDestroy等注解都属于该类型
factory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(item->{
item.postProcessBeanFactory(factory);
});
Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);
}
但是在该代码的基础上,调用factory.getBean(Bean1.class).getBean2()
方法,得到的结果是null,因为getBean2返回的是一个Bean2对象,而在Bean1的class中,Bean2对象使用的是@Autowired注解进行注入,也就表示,该注入并未成功。也就表示BeanFactoryPostProcessor.class
没有对@Autowired进行处理。
修改后如下:
//bean后置处理器,针对的是Bean的生命周期的各个阶段提供扩展。如@Autowired、@Resource等
factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor);
System.out.println(factory.getBean(Bean1.class).getBean2());
Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);
BeanFactoryPostProcessor 针对的是Bean工厂,先将其加入Bean工厂,BeanPostProcessor针对的是Bean ,再与Bean建立联系
以@Autowired 和 @Resource 为例
在上述代码基础上,加入
interface Inter {
}
static class Bean3 implements Inter {
}
static class Bean4 implements Inter {
}
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;
}
@Autowired
private Inter inter;
public Inter getInter() {
return inter;
}
}
首先对Inter 接口使用@Autowired进行注入,之后调用getInteger()方法
System.out.println(factory.getBean(Bean1.class).getInter());
会出现该错误
因为@Autowired注解,会先根据类型去查找,之后再回根据类型进行查找。在这个例子中,@Autowired注解先根据类型找到了Bean3和Bean4(这两个都是实现了Inter接口),之后因为没有唯一的实现,所以会根据名字去查找,而此时的命名为Inter inter ,所以@Autowired找不到对应的类进行注入,就会抛出异常。
在此可以使用两种解决方法:
-
将Inter inter 命名改为 Inter bean3 或 Inter bean4 ,指明要注入额Bean的名称,由此找到对应的类。
-
使用@Resource注解指定具体的name
@Resource(name = "bean3") private Inter inter;
如果两种注解同时使用的话,情况分析::::::
@Resource(name = "bean3")
@Autowired
private Inter inter;
此时仍会抛出异常
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.example.demo.test.BeanFactoryTest$Inter’ available: expected single matching bean but found 2: bean3,bean4
其原因是因为@Autowired的优先级高于@Resource,所以@Autowired生效了
//bean后置处理器,针对的是Bean的生命周期的各个阶段提供扩展。如@Autowired、@Resource等
factory.getBeansOfType(BeanPostProcessor.class).values().stream().forEach(item->{
System.out.println(item);
factory.addBeanPostProcessor(item);
});
在该代码出加个输出,即在将后置处理器加入BeanPostProcessor时,进行一个输出,看一下先后顺序,结果如下
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@1e683a3e
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@2053d869
由此可以看出@Autowired的优先级高于@Resource
因为在将这些后置处理器加入到BeanPostProcessor是,有一个优先级的先后顺序,也可以人为的进行改变。如下::::
factory.getBeansOfType(BeanPostProcessor.class).values()
.stream().sorted(factory.getDependencyComparator()).
forEach(item->{
System.out.println(item);
factory.addBeanPostProcessor(item);
});
执行结果:::::
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@3e84448c
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@4a7f959b
是因为,在CommonAnnotationBeanPostProcessor类和AutowiredAnnotationBeanPostProcessor类中,有一个优先级的字段order,比较器会根据order的大小进行优先级排序
CommonAnnotationBeanPostProcessor:::
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
AutowiredAnnotationBeanPostProcessor:::
private int order = Ordered.LOWEST_PRECEDENCE - 2;
由此可以看出CommonAnnotationBeanPostProcessor对应的值小,所以优先级高,因此人为排序后的@Resource的优先级大于@Autowried。
3-14
Bean的生命周期
Bean流程测试
@Component
public class LifeCycleBeanTest {
private static final Logger log = LoggerFactory.getLogger(LifeCycleBeanTest.class);
public LifeCycleBeanTest() {
log.debug("构造方法");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String javacHome){
log.debug("依赖注入:{}",javacHome);
}
@PostConstruct
public void init(){
log.debug("初始化");
}
@PreDestroy
public void destroy(){
log.debug("销毁");
}
}
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
run.close();
}
}
创建方法后进行debug,可以看到输出如下:
com.example.demo.test.LifeCycleBeanTest : 构造方法
com.example.demo.test.LifeCycleBeanTest : 依赖注入
com.example.demo.test.LifeCycleBeanTest : 初始化
com.example.demo.test.LifeCycleBeanTest : 销毁
也就是当一个类加上Component注解后,进行扫描时,会先执行其构造方法也就是实例化。之后会对相关的加有依赖注入的注解进行依赖注入,如果有@PostConstruct注解,表示在初始化时进行一些操作,@PreDestroy表示在这个实例销毁时进行一些操作
使用后置处理器对Bean进行操作
可以在Bean的实例化、依赖注入、初始化、销毁等操作时,对其进行一些额外的操作,如下:
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBeanTest")){
log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<销毁前执行,如@PreDestory>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBeanTest")){
log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<实例化之前执行,在这里返回的对象可以替换掉原来的bean>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBeanTest")){
log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<实例化之后执行,如果这里返回false会跳过依赖注入阶段>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
return false;
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBeanTest")){
log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<依赖注入阶段执行,例如:@Autowired、@Value、@Resource>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBeanTest")){
log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<初始化之前执行,返回对象可替换原本的bean,如@PostConstruct 、@ConfigurationProperties>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBeanTest")){
log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<初始化之后执行,返回的对象会替换掉原本的bean,如代理增强>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
return bean;
}
}
3-15
后置处理器
bean后置处理器
创建Bean1、Bean2、Bean3
public class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
private Bean2 bean2;
public Bean1() {
log.debug("Bean1无参构造");
}
@Autowired
public void setBean2(Bean2 bean2) {
log.debug("@Autowired生效:{}", bean2);
this.bean2 = bean2;
}
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.debug("@Resource生效:{}", bean3);
this.bean3 = bean3;
}
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME}") String home) {
log.debug("@Value生效:{}",home);
this.home = home;
}
@PostConstruct
public void init(){
log.debug("@PostConstruct生效");
}
@PreDestroy
public void destroy(){
log.debug("@PreDestroy生效");
}
}
public class Bean2 {
}
public class Bean3 {
}
主启动类
public class Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
//注册Bean1 、 Bean2 、 Bean3
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
//Autowired等注解的后置处理器,去掉后就不会对Autowired进行自动注入
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
//@Resource 、@PostConstruct、 @PreDestroy等注解的后置处理器。。。。。
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.refresh();
context.close();
}
}