主件注冊(cè)
- @Configuration
@Configuration即用來(lái)代替Spring配置文件的车柠,它就是一個(gè)@Component組件,接收一個(gè)value值也就是bean的名字骡尽,value可以不填遣妥。Spring會(huì)自動(dòng)掃描包下面的@Configuration注解的配置文件類(lèi)來(lái)裝配。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
- @Bean
@Bean相當(dāng)于Spring配置文件中的<bean />標(biāo)簽可以在Spring容器中注入一個(gè)bean:
- 1. @Bean注解在返回實(shí)例的方法上攀细,如果未通過(guò)@Bean指定bean的名稱(chēng)箫踩,則默認(rèn)與方法名相同
- 2. @Bean注解默認(rèn)作用域?yàn)閱卫齭ingleton作用域,可通過(guò)@Scope(“prototype”)設(shè)置為多例
@Configuration
public class TestConfiguration {
@Bean
public TestBean testBean() {
return new TestBean();
}
}
上面的代碼就會(huì)向Spring容器中實(shí)例一個(gè)TestBean對(duì)象谭贪,并且該Bean對(duì)象的名稱(chēng)為testBean
- @ComponentScan
@ComponentScan 的作用就是根據(jù)定義的掃描路徑境钟,把符合掃描規(guī)則的類(lèi)裝配到spring容器中。注意:被掃描的包下面的類(lèi)只能有以下注解俭识,才會(huì)被創(chuàng)建加入到IOC中去:
- 1. @Component:沒(méi)有明確的角色
- 2. @Service:業(yè)務(wù)層角色
- 3. @Repository:持久層角色
- 4. @Controller:控制層角色
注解定義如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
String resourcePattern() default "";
boolean useDefaultFilters() default true;
ComponentScan.Filter[] includeFilters() default {};
ComponentScan.Filter[] excludeFilters() default {};
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
- 1.basePackages與value: 用于指定包的路徑慨削,進(jìn)行掃描
- 2.basePackageClasses: 用于指定某個(gè)類(lèi)的包的路徑進(jìn)行掃描
- 3.nameGenerator: bean的名稱(chēng)的生成器
- 4.useDefaultFilters: 是否開(kāi)啟對(duì)@Component,@Repository套媚,@Service缚态,@Controller的類(lèi)進(jìn)行檢測(cè),默認(rèn)開(kāi)啟
- 5.includeFilters: 包含的過(guò)濾條件:
FilterType.ANNOTATION:按照注解過(guò)濾
FilterType.ASSIGNABLE_TYPE:按照給定的類(lèi)型
FilterType.ASPECTJ:使用ASPECTJ表達(dá)式
FilterType.REGEX:正則
FilterType.CUSTOM:自定義規(guī)則
- 6.excludeFilters: 排除的過(guò)濾條件:
FilterType.ANNOTATION:按照注解過(guò)濾
FilterType.ASSIGNABLE_TYPE:按照給定的類(lèi)型
FilterType.ASPECTJ:使用ASPECTJ表達(dá)式
FilterType.REGEX:正則
FilterType.CUSTOM:自定義規(guī)則
- 7.lazyInit:是否進(jìn)行懶加載,默認(rèn)為false
例子:
工程目錄結(jié)構(gòu)如圖:
1.掃描service包下的類(lèi):
@Configuration
@ComponentScan(value = "com.xhx.spring.service",useDefaultFilters = true)
public class MyConfig {
}
2.掃描service包下的類(lèi)和HelloController類(lèi)所在包下的所有類(lèi)
@Configuration
@ComponentScan(value = "com.xhx.spring.service",
useDefaultFilters = true,
basePackageClasses = HelloController.class
)
public class MyConfig {
}
3.只掃描指定包下的Controller注解標(biāo)記的類(lèi)添加到IOC容器中去
@Configuration
@ComponentScan(value = "com.xhx.spring",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
}
)
public class MyConfig {
}
4.掃描指定包下指定類(lèi)型的類(lèi)到IOC容器中堤瘤。(即使指定類(lèi)型的類(lèi)沒(méi)有加注解也能被掃描到IOC容器中去)
@Configuration
@ComponentScan(value = "com.xhx.spring",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {HelloController.class})
}
)
public class MyConfig {
}
這里即使HelloController類(lèi)沒(méi)有加@Controller猿规、@Service、@Component宙橱、@Repository注解也能被掃描到IOC容器中去。
5.指定包路徑蘸拔,按照自定義掃描規(guī)則進(jìn)行掃描
自定義掃描規(guī)則:自定義規(guī)則必須實(shí)現(xiàn)TypeFilter
接口
package com.xhx.spring.componentscan.config;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
/**
* 2018/9/18 23:07
**/
public class MyTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//MetadataReader該參數(shù)可以獲取指定路徑下所有類(lèi)的任何信息
//MetadataReaderFactory是MetadataReader工廠
String className = metadataReader.getClassMetadata().getClassName();
if(className.contains("Controller")){
return true;
}
return false;
}
}
自定義配置類(lèi):
@Configuration
@ComponentScan(value = "com.xhx.spring",
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
}
)
public class MyConfig {
}
- @Scope
spring中scope是一個(gè)非常關(guān)鍵的概念师郑,簡(jiǎn)單說(shuō)就是對(duì)象在spring容器(IOC容器)中的生命周期,也可以理解為對(duì)象在spring容器中的創(chuàng)建方式调窍。
scope分類(lèi):
在Spring 2.0之前宝冕,有singleton和prototype兩種;
在Spring 2.0之后邓萨,為支持web應(yīng)用的ApplicationContext地梨,增強(qiáng)另外三種:request,session和global session類(lèi)型缔恳,它們只實(shí)用于web程序宝剖,通常是和XmlWebApplicationContext共同使用。
- @Lazy
該注解是在單實(shí)例bean是使用歉甚,當(dāng)使用@Scope注解的singleton屬性時(shí)万细,bean的實(shí)例會(huì)在IOC容器創(chuàng)建的時(shí)候被加載,但是如果在創(chuàng)建bean的時(shí)候加上@lazy注解纸泄,則bean的實(shí)例會(huì)在第一次使用的時(shí)候被創(chuàng)建赖钞。
@Lazy
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)//singleton
@Bean(name = "person")
public Person person(){
Person person = new Person();
person.setName("lqf");
person.setEmail("lqf@163.com");
return person;
}
- @Conditional
@Conditional 注解腰素,根據(jù)是否滿(mǎn)足指定的條件來(lái)決定是否裝配 Bean 。Conditional 是由 SpringFramework 提供的一個(gè)注解雪营,位于 org.springframework.context.annotation 包內(nèi)弓千,定義如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition}s that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
Conditional 注解類(lèi)里只有一個(gè) value 屬性,需傳入一個(gè) Condition 類(lèi)型的數(shù)組献起,我們先來(lái)看看這個(gè) Condition 接口長(zhǎng)什么樣:
@FunctionalInterface
public interface Condition {
/**
* Determine if the condition matches.
* @param context the condition context
* @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
* or {@link org.springframework.core.type.MethodMetadata method} being checked
* @return {@code true} if the condition matches and the component can be registered,
* or {@code false} to veto the annotated component's registration
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
其中洋访,matches() 方法傳入的參數(shù) ConditionContext 是專(zhuān)門(mén)為 Condition 而設(shè)計(jì)的一個(gè)接口類(lèi),可以從中獲取到Spring容器的以下對(duì)象信息:
- ConditionContext
- getRegistry():獲取BeanDefinitionRegistry
- getBeanFactory():獲取ConfigurableListableBeanFactory
- getEnvironment():獲取Environment
- getResourceLoader():獲取ResourceLoader對(duì)象
- getClassLoader():獲取ClassLoader對(duì)象
當(dāng)一個(gè) Bean 被 Conditional 注解修飾時(shí)征唬,Spring容器會(huì)對(duì)數(shù)組中所有 Condition 接口的 matches() 方法進(jìn)行判斷捌显,只有當(dāng)其中所有 Condition 接口的 matches()方法都為 ture 時(shí),才會(huì)創(chuàng)建 Bean 总寒。
- @Import
@Import可以導(dǎo)入一些有規(guī)律的組件扶歪。@Import定義如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* or regular component classes to import.
*/
Class<?>[] value();
}
-
1.導(dǎo)入普通類(lèi)型:
Student
類(lèi):
public class Student {
}
配置類(lèi):
@Configuration
@Import(Student.class)
public class ImportConfig {
}
-
2.
ImportSelector
選擇一些需要導(dǎo)入的組件
MySelector 類(lèi):
public class MySelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"me.sjl.bean.Person"};
}
}
配置類(lèi):
@Configuration
@Import(MySelector.class)
public class ImportConfig {
}
-
3.
ImportBeanDefinitionRegistrar
導(dǎo)入添加BeanDefinition中的組件
MyBeanDefinitionRegistrat :
public class MyBeanDefinitionRegistrat implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
registry.registerBeanDefinition("PERSON", beanDefinition);
}
}
配置類(lèi):
@Configuration
@Import(MyBeanDefinitionRegistrat.class)
public class ImportConfig {
}
生命周期
Bean的生命周期:bean創(chuàng)建 —— 初始胡 —— 銷(xiāo)毀過(guò)程
- @Bean(initMethod="",destroyMethod="")
通過(guò)@Bean
注解中的initMethod和destroyMethod屬性指定初始化方法和銷(xiāo)毀方法。
創(chuàng)建一個(gè)Person類(lèi)摄闸,并指定初始化方法和銷(xiāo)毀方法:
public class Person{
public Person(){
System.out.println("person controct ...");
}
public init(){
System.out.println("person init ...");
}
public destroy(){
System.out.println("person destroy ...");
}
}
創(chuàng)建配置類(lèi)善镰,把Person類(lèi)注進(jìn)到IOC容器中,并指定初始化方法和銷(xiāo)毀方法:
@Configuration
public class MyConfiguration{
@Bean(initMethod="init",destroyMethod="destroy")
public Person person(){
return new Person();
}
}
- InitializingBean
和DisposableBean
接口
通過(guò)讓Bean實(shí)現(xiàn)InitializingBean
接口定義初始化邏輯年枕,實(shí)現(xiàn)DisposableBean
接口定義銷(xiāo)毀邏輯
創(chuàng)建一個(gè)Dog類(lèi)炫欺,并實(shí)現(xiàn)InitializingBean
接口和DisposableBean
來(lái)定義初始化邏輯和銷(xiāo)毀邏輯:
@Component
public class Dog implements InitializingBean,DisposableBean {
public Dog(){
System.out.println("Dog controcter");
}
//銷(xiāo)毀方法
@Override
public void destroy() throws Exception{
System.out.println("Dog destory ...");
}
//初始化方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Dog afterPropertiesSet ...");
}
}
- @PostConstruct
和 @PreDestroy
通過(guò)使用JSR250:@PostConstruct
注解(該注解標(biāo)注在方法上,在bean創(chuàng)建完成后熏兄,并且屬性賦值完成品洛,就來(lái)執(zhí)行該注解標(biāo)注的方法進(jìn)行初始化)。@PreDestroy
注解(該注解標(biāo)注在方法上摩桶,當(dāng)容器銷(xiāo)毀前通知該注解標(biāo)記的方法進(jìn)行清理相關(guān)的工作)桥状。
創(chuàng)建一個(gè)Car類(lèi),并通過(guò)@PostConstruct
和 @PreDestroy
標(biāo)記的初始化方法和銷(xiāo)毀方法:
@Component
public class Car{
public Car(){
System.out.println("Car constructor ...");
}
@PostConstruct
public void init(){
System.out.println("Car init ...");
}
@PreDestroy
public void destroy(){
System.out.println("Car destroy ...");
}
}