Spring知识盘点(注解)
一.
(最初由读取手动传参引发的问题,后来又想在Controller里面改最底层依赖的bean)
1. 问题的核心是Bean和普通的new对象
(1) @Component注解是把一个类注册成了Spring的控制bean,由这个注解衍生出来的@Controller、@Service、@Repository和@Configuration。
(@Configuration注解是这个类里面包含了一大堆的bean,@Component注解是把这个类注册成了bean。)
/* 现在稍微能理解一点@Configuration这个东西了,这个类里面只有几个变量,没啥方法,但是这几个变量又需要用Spring去创建,于是就搞这么一个Configuration。 */
@Component和@Bean的区别:@Component是把这个类注册成了Bean,把这个Bean实例化的时候应该只能是走无参构造函数,然后运行一些初始化的流程什么的。而@Bean是手动显式生成Bean,这个你就要自己去new自己运行各种构造函数,然后生成一个对象出来,把这个对象注册成Bean,就不是类了。
@Bean需要放在@Configuration里面,保证能运行到这个类,然后把这些Bean给注册进去。
(2) Bean的初始化和销毁
如果是获取Bean,用那些@Autoweired或者是context.getBean()这些去拉一个Bean出来,Spring中间肯定拦截,用AOP增强,把这个Bean的各种变量都初始化了,所以在这个类里面打的什么@Value注解之类的就都用上了。
如果自己new了一个,那就只走了java的流程,Spring根本没用上,没拦截,没注入,自然是不行的。
Autowired的实际等效并不是new,而是Spring给你去getBean,在这个过程中如果有@Valid什么注解都会生效。如果是new的话这些东西就都没有了,只走java的流程。
(3) @Configuration和@ConfigurationProperties这两个注解的区别。
目前先粗略理解,这两个注解发挥的作用可以是一样的,都可以从yml里面读东西注入到类里面去。
如果用@Configuration的话,它的@Valid("${ }"),那里面就要写全,从spring.profile.active这些都要写全,前缀很多。
@ConfigurationProperties可以指定前缀,那样的话这些变量只要指定具体哪条的子名称就行了,不用把前缀写那么多遍。
(@ConfigurationProperties可以被看成是从yml里面,抽出一段来,用这一段来构建出一个类)
(4)从命令行读取参数,还是用了@Value注解,原理都一样
java -jar xxx.jar --a1=aaa --b1=bbb
是springboot的写法,可以通过@Value("${a1}") 获取
二. Spring注解
1. @Configuration注解
这个@Configuration注解是要跟@Bean注解联系在一起看的,然后把这两个注解都变成xml的形式来看,变成xml理解就方便多了。
@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文)。
@Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的<bean>,作用为:注册bean对象。
实例:
@Configuration
//添加自动扫描注解,basePackages为TestBean包路径
@ComponentScan(basePackages = "com.cqupt.meeting.config")
public class TestConfig {
/*
这个方法上面没有@Bean,但是这个方法也会被运行,主类运行的时候这一行会被输出。
*/
public TestConfig(){
System.out.println("testconfig collection init success");
}
// @Bean注解注册bean,同时可以指定初始化和销毁方法
// @Bean(name="testBean",initMethod="start",destroyMethod="cleanup")
// @Scope("prototype")
@Bean
public TestBean testBean() {
return new TestBean();
}
}
上面是一段@Configuration的例子,Spring里面的注册Bean也就是一个方法,这个方法的返回值是一个对象,然后在方法上面打上@Bean,Spring自动运行这个方法,然后把返回值注册成Bean。
可以这么理解@Configuration,只要一个类打上了这个注解,Spring就会把这个类里面的每一个方法都运行一遍,运行的方法上面有@Bean自然就被注册了,没有的也运行,该输出就输出。
主类@SpringBootApplication这个注解里面应该也集成了@Configuration注解,你可以反过来理解,吧@Configuration当成主类,只要程序运行的时候,主类和@Configuration都跑起来。
<?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="testBean2" class="com.cqupt.meeting.config.TestBean2">
<property name="username" value="ranjun"></property>
</bean>
</beans>
这是一个<beans>的实例,Spring主类运行的时候,应该先装载这些bean,等这些上下文环境都配好了之后,再运行其他程序。
2. @ComponentScan
那些被注册成@Component、@Configuration、@Service的Bean,是要被扫描到Springboot里面才能发挥作用的。
不过Springboot主类里面的@SpringBootApplication注解里面自带了@ComponetScan注解,发挥的作用应该是扫描主类同级及以下的所有目录。
三. Bean的生命周期
1. 单例模式和多例模式
单例模式是构造函数私有,只能在这个类里面构造一个,然后别人请求的时候,把已经有的这一个成员变量返回回去。
而多例模式,并不是构造很多个不同的Bean,而是构造很多相同的Bean,然后控制这些Bean的数量。比如连接池里面的连接。多例模式跟单例模式挺像的,是单例模式的扩展。
2. @Scope(value = "prototype")
@Service
@Scope(value = "prototype")
public class TestService {}
如果打上了这个Scope,变成多例模式的话,每次调用这个都会new一个Bean。
如果Controller1是单例,Service1是多例,Service2是多例,那也只生成一次。
如果Controller2是多例,Service1是多例,Service2是多例,每次请求三个都会生成新的。
3. @Autowierd和@Resource
Autowired只能按照类型来注入,这个类只能生成一个Bean,天生就是支持单例模式的。
Resource(name = "....")这个按照名字注入,摆明了这个类会生成多个Bean。
以及Autowired应该没有任何神奇的地方,这只是一个getBean,单例还是多例是那个bean决定的,跟是不是Autowired没关系。(不过Autowired确实不支持多例)
4. Bean的初始化顺序
一定是先生成Service的Bean,再生成Controller的Bean,然后把Service装到Controller里面去。
5. 初始化的各个方法
一个类生成的Bean要被多处使用,多例模式的时候估计会用到这些方法。
1 construct
2 PostConstruct
3 afterPropertiesSet
4 init
创建:Bean 构造函数 ——> @Autowired——> @PostConstruct ——> InitializingBean 接口 ——> bean 定义的 init-method