@Configuration : 配置類 == 配置文件,告訴Spring這是一個配置類@ComponentScan(value="com.atguigu",excludeFilters = { @Filter(type=FilterType.ANNOTATION,classes={Controll ...
@Configuration : 配置類 == 配置文件,告訴Spring這是一個配置類
@ComponentScan(value="com.atguigu",excludeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
@ComonentScan value : 指定要掃描的包(這個註解可以定義多個)
excludeFilters = Filter[] : 指定掃描的時候按照什麼規則排除那些組件
includeFilters = Filter[] : 指定掃描的時候只需要包含那些組件
useDefaultFilters = false : 表示去掉預設掃描
FilterType.ANNOTATION : 按照註解類型 例如 : Controller.class
FilterType.ASSIGNABLE_TYPE : 按照給定的類型 例如 : UserService.class
FilterType.ASPECTJ : 使用ASPECTJ表達式
FilterType.REGEX : 使用正則指定
FilterType.CUSTOM : 使用自定義規則
自定義規則需要實現TypeFilter介面
public class MyTypeFilter implements TypeFilter {
/**
metadataReader : 讀取到的當前正則掃描的類的信息
metadataReaderFactory : 可以獲取到其他任何類的信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {
// 獲取當前類註解的信息
AnnotationMetadata annotationMetadate = metadataReader.getAnnontationMetadata();
// 獲取當前正在掃描的類的類信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 獲取當前類資源(類的路徑)
Resource resource = metadataReader.getResource();
// 獲取這個類名
String className = classMetadata.getClassName();
// 自定義匹配規則
if(className.contains("er")) {
return true;
}
return false;
}
}
@ComponentScans(
value {
@ComponentScan(value="com.atguigu",excludeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
}, useDefaultFilters = false)
}
) : 裡面可以定義多個@ComponentScan
@Bean : 給容器中註冊一個Bean;類型為返回值的類型,id預設是用方法名作為id
@Scope("") : 表示這個對象或者這個bean的創建作用域範圍(調整作用域).
prototype : 多實例的,ioc容器時並不會調用方法創建對象放在容器中.每次獲取的時候才會調用方法創建對象.
singleton : 單實例的(預設值),ioc容器啟動會調用方法創建對象放到ioc容器中.以後每次獲取就是直接從容器(map.get())中拿.
request : 同一次請求創建一個實例
session : 同一個session創建一個實例
@Lazy : 懶載入
單實例bean,預設在容器啟動的時候創建對象.
懶載入: 容器啟動不創建對象,第一次調用(獲取)Bean創建對象,並初始化.
@Conditional({Condition}) : 按照一定的條件進行判斷,滿足條件給容器中註冊bean(可以放在@Bean上,或者類上)
例如 :
//放在類上統一設置
// 類中組件統一設置,滿足當前條件,這個類中配置的所有bean註冊才能生效.
@Conditional({WindowsCondition.class})
@Configuration
//實現介面Condition
public class LinuxCondition implements Condition {
/**
*/
public boolean matchs(CondititContext context, AnnotatedTypeMetadata metadada) {
// 是否linux系統
// 1. 能獲取到ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 2.獲取類載入器
ClassLoader classLoader = context.getClassLoader();
// 3.獲取當前環境信息
Environment environment = context.getEnvironment();
// 4.獲取到bean定義的註冊類(可以判斷容器中的bean註冊情況,也可以給容器中註冊bean)
BeanDefinitionRegistry registry = context.getRegistry();
// 判斷容器中是否包含bean
boolean definition = registry.containsBeanDefinition("persion");
String property = environment.getProperty("os.name");
if (property.contains("linux")){
return true;
}
return false;
}
}
// 獲取bean名稱
String[] namesForType = applicatinContext.getBeanNamsForType();
// 動態獲取環境變數的值,獲取容器運行環境例如 : windows,liunx
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 獲取操作系統的名稱
String property = environment.getProperty("os.name");
給容器中註冊組件 :
1 : 包掃描+組件標註註解(@Controller/@Service/@Repository/@Component)
2 : @Bean[導入的第三方包裡面的組件]
3 : @Import[快速給容器中導入一個組件]
1) : @Import(要導入到容器中的組件);容器中就會自動註冊這個組件,id預設是組件的全類名(也可以導入多個組件)
2) : ImportSelector : 返回需要導入的組件的全類名數組.
3) : ImportBeanDefinitionRegistrar : 手動註冊Bean到容器中
4 : 使用Spring提供的FactoryBean(工廠Bean)
1) : 預設獲取到的是工廠bean調用getObject創建的對象
2) : 要獲取工廠Bean本身,我們需要給id前面加一個&
&colorFactoryBean
@Import(要導入到容器中的組件 例如 : Color.class) : 方在類上,導入組件,容器中就會自動註冊這個組件,id預設是組件的全類名(也可以導入多個組件)
(2) ImportSelector : 返回需要導入的組件的全類名數組.
例如 :
//自定義邏輯返回需要導入的組件
public class MyImportSelector implements ImportSelector {
// 返回值,就是導入到容器中的組件全類名
// AnnotationMetadata : 當前標註@Import註解的類的所有註解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 方法不要返回null值
return new String[];
}
}
@Import({Color.class,Red.class,MyImportSelector.class})
(3) ImportBeanDefinitionRegistrar : 手動註冊Bean到容器中
例如 :
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
// AnnotationMetadata : 當前類的註解信息
// BeanDefinitionRegistry : BeanDefinitionRegistry註冊類;
// 把所有需要添加到容器中的bean : 調用 BeanDefinitionRegistry.registryBeanDefinition手工註冊進來
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
// 通過bean名稱,判斷bean是否在容器中
booean definition = registry.containsBeanDefinition("red");
boolean definition1 = registry.containsBeanDefinition("blue");
if (definition && definition1) {
// 指定bean定義信息 : (Bean的類型,Bean...)
RootBeanDefinition bean = new RootBeanDefinition(RainBow.class);
// 註冊一個Bean,指定Bean名
registry.registryBeanDefinition("rainBow", bean);
}
}
}
4 : 例子 :
// 創建一個Spring定義的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
// 返回一個Color對象,這個對象會添加到容器中
@Override
public Color getObject() throws Exception {
return new Color();
}
public Class<?> getObjectType() {
return Color.class;
}
//是單例?
//true : 這個bean是單例,在容器中保存一份
//false : 多實例,每次獲取都會創建一個新的bean
@Override
public boolean isSingleton() {
return false
}
}
@Bean
public ColorFactoryBean getBean() {
return new ColorFactoryBean();
}
public void test() {
//工廠Bean獲取的是調用getObject創建的對象;實際上獲取的是Color對象
Object bean2 = applicatinContext.getBean("colorFactoryBean");
//這個是獲取的ColorFactoryBean對象,因為在FactoryBean介面中定義了一個字元串,表示以&開頭的就是獲取實現FactoryBean介面的對象
Object bean3 = applicatinContext.getBean("&colorFactoryBean");
}
Bean的生命周期
bean創建 -- 初始化 -- 銷毀的過程
容器管理bean的生命周期 :
我們可以自定義初始化和銷毀方法;容器在bean進行到當前生命周期的時候來調用我們自定義的初始化和銷毀的方法
構造(對象創建)
單實例 : 在容器啟動的時候創建對象
多實例 : 在每次獲取的時候創建對象
BeanPostProcessor.postProcessBeforeInitialization
初始化 :
對象創建完成,並賦值好,調用初始化方法...
BeanPostProcessor.postProcessInitialization
銷毀 :
單實例 : 容器關閉的時候
多實例 : 容器不會管理者bean,容器不會調用銷毀方法.
遍歷得到容器中所有的BeanPostProcessor : 挨個執行beforeInitialization,一旦返回null,跳出for迴圈,不會執行後面的BeanPostProcessor.postProcessBeforeInitialization
BeanPostProcessor的原理
populateBean(beanName, mdb, instanceWrapper) : 給bean進行屬性賦值
initializeBean
{
appliyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
}
1) : 指定初始化和銷毀方法:
通過@Bean指定init-method和destory-method;
2) : 通過讓Bean實現InitializingBean(定義初始化邏輯),DisposableBean(定義銷毀邏輯)
3) : 可以使用JSR250;
@PostConstruct : 在bean創建完成並且屬性賦值完成;來執行初始化方法(在對象創建並賦值之後調用)
@PreDestroy : 在容器銷毀bean之前通知我們進行清理工作.
例如 :
public class Dog{
public Dog() {
System.out.println("");
}
//對象創建並賦值之後調用
@PostConstruct
public void init() {
System.out.println("11");
}
//容器移除對象之前
@PreDestroy
public void detory(){
}
}
4) : BeanPostProcessor[interface] : bean後置處理器;
在bean初始化前後進行一些處理工作;
postProcessBeforeInitialization : 在初始化之前工作
postProcessInitialization : 在初始化之後工作
Spring底層對BeanPostProcessor的使用 :
bean賦值,註入其他組件,@Autowired,生命周期註解功能。@Async, xxx BeanPostProcessor;
@Value : 給屬性賦值。
1. 基本數值 例如 : @Value("111")
2. 可以寫SpEL. 例如 : @Value("#{20-2}")
3. 可以寫${},取出配置文件中的值(在運行環境變數裡面的值) 例如 : @Value("${name}")
@PropertySource讀取外部配置文件中的k/v保存到運行的環境變數中;載入完外部的配置文件以後使用${}取出配置文件的值。
例如 :
AnnotationConfigApplicationContext applicatinContext = new AnnontationConfigApplicationContext();
pringBeans(applicationContext);
Person person = (Person)applicationContext.getBean("person");
ConfigurableEnvironment environment = applicatinContext.getEnvironment();
// 這是根路徑下的.properties配置文件中的k/v值
Sting property = environment.getProperty("person.nickName);
applicatinContext.close();
自動裝配 :
Spring利用依賴註入(DI),完成對IOC容器中各個組件的依賴關係賦值;
1) . 預設優先按照類型去容器中找對應的組件 : applicationContext.getBean(BookDao.class);找到就賦值
2) . 如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找
3) . @Qualifier("bookDao") : 使用@Qualifier指定需要裝配的組件的id,而不是使用屬性名。
4) . 自動裝配預設一定要將屬性賦值好,沒有就會報錯。(可以通過更改屬性值.例如 : @Autowired(required=false);這樣就在沒有這個組件時,不會進行自動裝配)
5) . @Primary : 讓Spring進行自動裝配的時候,預設使用首選的bean;
也可以繼續使用@Qualifier指定需要裝配的bean的名字。
applicatinContext.getBean("bookDao");
BookService{
@Autowired
BookDao bookDao
}
(2):Spring還支持使用@Resource(JSR250)和@Inject(JSR330)【Java規範的註解】
@Resource
可以和@Autowired一樣實現自動裝配功能;預設是按照組件名稱進行裝配的;
沒有能支持@Primary功能沒有支持 @Autowired(reqiured = false);
@Inject
需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能;
@Autowired : Spring定義的; @Resouce和@Inject都是java規範。
Spring的@Autowired的底層使用AutowiredAnnotationBeanPostProcessor : 解析完成自動裝配功能。
(3):@Autowired : 構造器,參數,方法,屬性
@Componetnt : 預設載入ioc容器中的組件,容器啟動會調用無參構造器創建對象,再進行初始化賦值等操作
1): 標註在方法位置 : @Bean + 方法參數;參數從容器中獲取;預設不寫@Autowired效果是一樣的,都能自動裝配
2): 標註在構造器上 : 如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件換是可以自動從容中獲取.
3):標註在參數位置
@Bean標註的方法創建對象的時候,方法參數的值從容器中獲取。
(4) : 自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx);自定義組件實現xxxAware;在創建對象的時候,會調用介面規定的方法註入相關組件;Aware
把Spring底層一些組件註入到自定義的Bean中;
xxxAware: 功能使用xxxProcessor;
ApplicationContextAware ==> ApplicationContextAwareProcessor;
@Profile : 指定組件在哪個環境的情況下才能被註冊到容器中。
1) : 加了環境標識的bean,只有這個環境被激活的時候才能註冊到容器中。預設是default環境。
2) : 寫在配置上,只有是指定的環境的時候,整個配置類裡面的所有配置才能開始生效。
激活方式 :
(1) : 使用命令行動態參數 : 在虛擬機參數位置載入 -Dspring.profiles.active=test
(2) :代碼的方式激活某種環境。
(3) : 沒有標註環境標識的bean在任何環境下都是載入的。
例如 :
AnnotationConfigApplicationContext applicatinContext = new AnnontationConfigApplicationContext();
//1。創建一個applicationContext
//2. 設置需要激活的環境
applicatinContext.getEnvironment().setActiveProfiles("dev");
//3.註冊主配置類
applicatinContext.registry(MainConfigOrProfile.class);
//4.啟動刷新容器
applicatinContext.refresh();