Spring中的註解_學習筆記
1. @Configuration 配置註解
用xml的配置方式時匯入元件至容器時需要在xml新增標籤,並進行賦值等,利用註解的方式後只需新建一個配置類,在類上新增@Configuration
,類中寫相應的方法,返回需要的型別即可,需要在方法上新增@bean
註解; 這種方式的元件名為預設為方法名;
2. @ComponentScan 掃描註解
spring預設掃描只會掃描啟動類所在包及子包,需要指定包掃描路徑,以前用xml配置需要新增<context:component-scan base-package="com.xxx"/>
@ComponentScan
註解,並指定路徑即可;省略了配置檔案新增包掃描。
@ComponentScan("com.atguigu")
public class MainFunction {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainFunction.class);
String[] names = context. getBeanDefinitionNames();
for(String name:names) {
System.out.println(name);
}
}
}
親測: 其實新增包掃描註解可以在任何一個元件上指定,且可以多次指定;
//@ComponentScan("com.atguigu")
public class MainFunction {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext (UserDao.class);
String[] names = context.getBeanDefinitionNames();
for(String name:names) {
System.out.println(name);
}
}
}
//
@Repository
//@ComponentScan("com.atguigu")
@ComponentScan("com.atguigu.config")
public class UserDao {
}
上面把啟動類上的包掃描注掉,啟動時載入UserDao元件,而在UserDao元件中再新增掃描路徑,可得到不同的輸出結果;
注: 掃描的前提,該元件必須標註了spring容器能夠識別的標識(註解);
2.1 @ComponentScan註解中的屬性
value:
指定要掃描件的包
excludeFilters:
指定掃描的 時候按照什麼規則排除那些元件;
includeFilters
: 指定掃描的時候只需要包含哪些元件; 這個生效必須指定useDefaultFilters = false
此三個屬性都可以放陣列;
@ComponentScan(value = "com.atguigu",includeFilters = {@Filter(type =FilterType.ANNOTATION,classes = {Controller.class} )}
,excludeFilters = {@Filter(type = FilterType.ANNOTATION,classes = {Service.class})} ,useDefaultFilters = false)
public class MainFunction {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainFunction.class);
String[] names = context.getBeanDefinitionNames();
for(String name:names) {
System.out.println(name);
}
}
}
2.2 掃描過濾的型別
@Filter
註解中,type的型別可以是:
FilterType.ANNOTATION : 按照註解
FIlterType.ASSIGNABLE_TYPE : 按照給定的型別;
FilterType.ASPECTJ : 使用ASPECTJ表示式
FilterType.REGEX : 使用正則指定
FilterType.CUSTOM : 使用自定義規則
2.2.1 自定義過濾型別
僅需實現TypeFilter
介面即可,例如:⬇
public class MyTypeFilter implements TypeFilter{
/**
* metadataReader :讀取到的當前正在掃描的類的資訊
* metadataReaderFactory : 可以獲取到其他任何類資訊的
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// TODO Auto-generated method stub
// //獲取當前類註解的資訊
// AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// //獲取當前正在掃描的類的類資訊
// ClassMetadata classMetadata = metadataReader.getClassMetadata();
// //獲取當前類 類資源(路徑)
// Resource resource = metadataReader.getResource();
System.out.println("------->"+resource);
// String className = classMetadata.getClassName();
// System.out.println(">>>>>>>>>>>>>>>>>"+className);
//邏輯....
return false;
}
}
@ComponentScan(value = "com.atguigu",includeFilters = @Filter(type = FilterType.CUSTOM,classes =MyTypeFilter.class),useDefaultFilters = false)
public class MainFunction {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainFunction.class);
String[] names = context.getBeanDefinitionNames();
for(String name:names) {
System.out.println(name);
}
}
}
注: 使用自定義掃描時,指定的路徑下會掃描所有類,包括沒有新增三層註解的類。
3. @Scope
使用這個註解可以給Ioc容器中的bean設定作用域。xml的配置方式可以在標籤的屬性中設定;註解方式可以直接用@Scope
來完成;
元件的作用域有四種:
singleton: 單例(預設值) , ioc容器啟動會呼叫方法建立物件;以後每次用會從容器拿(map.get()
)
prototype: 多例項: ioc啟動時不會去呼叫方法建立,每次需要獲取時才會呼叫方法建立物件;
request : 同一個請求建立一個例項;
session: 同一個session 建立一個例項;
3.1 bean的懶載入
標註
@Lazy
註解的bean在容器初始化時不會被建立
懶載入只針對單例模式下。預設情況下單例模式在容器啟動的時候就會初始化bean,如果想單例模式下第一次獲取bean時再建立,可以給該bean設為懶載入,使用@Lazy
;
4. @Conditional 條件註解
按照一定的條件進行判斷,滿足條件給容器中註冊bean
從原始碼得知,@Conditional
註解的值是class型別(該型別集成了Condition)陣列,
編寫條件判斷
public class DogCondition02 implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO Auto-generated method stub
return true;
}
}
使用條件註解
@Bean
@Conditional(DogCondition02.class)
public Dog dog02() {
System.out.println("小黃222222出生了.......");
return new Dog("小黃", 3);
}
5. 元件匯入
給容器中註冊元件的方式
- 包掃描+元件標註註解(@Controller/@Service/@Repository/@Component)-----
有侷限性,不能匯入第三方的元件
@Bean
匯入的第三方包裡面的元件@Import
快速給容器中匯入一個元件
- @Import (要匯入到容器中的元件) : 容器中就會自動註冊這個元件,id預設是全類名;
- ImportSelector選擇器: 返回需要匯入的陣列的全類名陣列;
- ImportBeanDefinitionRegistrar:手動註冊
- 使用Spring提供的FactoryBean(工廠bean)
- 預設獲取到的是工廠bean呼叫getObject建立的物件
- 要獲取工廠bean本身,需要給id前面加
&
5.1 使用選擇器匯入元件
step1:編寫自定義元件選擇器,需要實現ImportSelector介面
//自定義元件選擇器,返回需要匯入的元件陣列
public class MyImportSelector implements ImportSelector{
/**
* 返回值: 匯入到容器中元件全類名
* AnnotationMetadata: 當前標註@Import註解的類的所有註解資訊
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// TODO Auto-generated method stub
return new String[] {"com.atguigu.bean.Blue","com.atguigu.bean.Red"};
}
}
step2: 用@Import註解匯入元件,示例程式碼中yell.class元件為Import單個匯入,在自定義選擇其中上面倒入了Blue和Red;
@Configuration
//@ComponentScan("com.atguigu")
@Import({MyImportSelector.class,Yell.class})
public class MainConfig {
// @Bean
// public Person getPerson() {
// return new Person("zhangsan",20);
// }
}
最終Ioc容器中包含了Blue,Red以及Yell元件;
5.2 ImportBeanDefinitionRegistrar 手動註冊
step1 : 編寫註冊器,需實現ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata : 當前類的註解資訊
* BeanDefinitionRegistry : BeanDefinition註冊類;把所有需要新增到容器中的bean:
* 呼叫 void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 指定bean定義資訊(bean型別,等...)
RootBeanDefinition beanDefinition = new RootBeanDefinition(Apple.class);
//註冊一個bean,指定bean名
registry.registerBeanDefinition("apple", beanDefinition);
}
}
step 2: 使用@Import時匯入編寫好的註冊器
5.3 使用FactoryBean 註冊元件
step1 : 建立自定義的FactoryBean,實現 FactoryBean介面
//建立一個Spring定義的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color>{ //泛型為要建立物件的型別
//返貨一個Color物件,這個物件會新增到容器中
public Color getObject() throws Exception {
// TODO Auto-generated method stub
return new Color();
}
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//建立的物件是不是單例
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
step2 : 在配置中新增bean元件
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
step3 : 獲取bean
1) 預設獲取到的是工廠bean呼叫getObject建立的物件
2) 要獲取工廠bean本身,需要給id前面加
&
@Test
public void test02() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Object bean = context.getBean("colorFactoryBean");
Object bean02 = context.getBean("&colorFactoryBean");
System.out.println("----------->>>"+bean.getClass());
System.out.println("----------->>>"+bean02.getClass());
}
6.元件/bean的生命週期相關注解
bean的生命週期大致分為: bean的建立 >> 初始化 >> 銷燬
執行構造(即物件的建立):
scope=singleton的例項:在容器啟動的時候建立;scope=prototype的例項:在每次獲取的時候建立物件;
6.1 通過指定初始化和銷燬方法來管理bean的建立過程
@Bean
註解中的屬性initMethod和destroyMethod設定響應的方法名
@Bean(initMethod = "init",destroyMethod = "destroy")
public Car car(){
return new Car();
}
//*******************
public class Car {
public Car() {
System.out.println("Car()..........");
}
public void init(){
System.out.println("Car ------init()");
}
public void destroy(){
System.out.println("car ---------destroy");
}
}
6.2 通過bean實現InitializingBean和DisposableBean的方式來管理bean的建立過程
6.3 使用JSR250中的@PostConstructh和@PreDestroy註解來管理
在初始化方法上新增@PostConstruct
,在銷燬方法上新增@PreDestroy
;