最近在整理一些spring相關的知識,就順帶在這記錄一下總結一下,給自己看也希望能幫助到一些正在學習以及一直在學習的夥伴。
本文內容記錄一下@Configuration註解的使用以及它與xml文件是如何對應的。
自從spring3.0開始,@Configuration可以用於定義配置了,也就是替代了過去xml配置,被註解的類內部含有一個或多個Bean,這些方法會被AnnotationConfigApplicationContext或者AnnotationConfigWebApplicationContext加載掃描,並構建Bean從初始化spring容器,類似於加載xml文件ClassPathXmlApplicationContext類加載xml文件。
一、@Bean的使用:使用此註解,表示在容器中註冊一個Bean,類型爲方法返回值的類型,id默認爲是方法名,也可以自行指定id,在xml中類似於一組<bean></bean>標籤,舉個簡單例子:
<bean id="person" class="bean.Person">
<property name="name" value="張三"></property>
<property name="age" value="18"></property>
</bean>
xml的使用
首先創建一個類並在xml中註冊一個Bean,id爲person,class寫出全路徑,並定義兩個屬性name和age,
在過去我們通過ClassPathXmlApplicationContext來加載xml文件,根據指定bean的id通過getBean(id)來獲取到Bean,例如:
public class MainTes {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Person bean = (Person) applicationContext.getBean("person");
System.out.println("person:"+bean);
//打印信息:person:Person{name='張三', age='18'}
}
}
@Bean註解的使用:
我們需要自定義一個類@Configuration來指定爲配置類等同於xml文件中的<beans></beans>,我們在類中註冊Bean
//配置類==配置文件
@Configuration //告訴spring這是一個配置類
public class MainConfig {
@Bean(name = "person") //在容器中註冊一個Bean;類型爲返回值的類型,id默認是用方法名作爲id,也可以自己指定name屬性爲id類型
public Person person(){
return new Person("李四","16");
}
}
通過AnnotationConfigApplicationContext類掃描加載
public class MainTes {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
//根據返回值類型來得到Bean
Person bean = applicationContext.getBean(Person.class);
//根據id來得到Bean
Person bean1 = (Person) applicationContext.getBean("person");
//獲取bean的id,也就是@Bean(name="person")中name的值,沒有的話就默認爲方法名作爲id。
String[] str = applicationContext.getBeanNamesForType(Person.class);
for (String st : str) {
System.out.println("str:" + st);
}
System.out.println("bean:" + bean);
System.out.println("bean1:" + bean1);
// 打印信息:
// str:person
// bean:Person{name='李四', age='16'}
// bean1:Person{name='李四', age='16'}
}
}
我們都能加載並得到容器中的Bean
也就是說
@Configuration等同於xml中的<beans></beans>
@Bean等同於xml中的<bean></bean>
二、包掃描組件:只要標註了@Controller、@Service、@Respository、@Component 都會被掃描到
在xml的配置中是這樣<context:component-scan bse-package=""></context:component-scan>,一般我們在指定base-package的時候都是寫包的根目錄,因爲它會自動掃描根目錄 下所有的包,只要標註了以上四個註解的都會被掃描到。
<context:component-scan base-package="bean"></context:component-scan>
<bean id="person" class="bean.Person">
<property name="name" value="張三"></property>
<property name="age" value="18"></property>
</bean>
在這我主要記錄一下@ComponentScan的使用:
@ComponentScan等同於上面xml配置文件的掃描組件:會自動掃描包路徑下面的所有@Controller、@Service、@Repository、@Component 的類
@ComponentScan裏的屬性:value指定掃描的包,includeFilters包含那些過濾,excludeFilters不包含那些過濾,useDefaultFilters默認的過濾規則是開啓的,如果我們要自定義的話是要關閉的。其中@Filters是一個過濾器的接口。
value屬性:點開spring定義的註解類ComponentScan我們可以發現value屬性默認爲一個String[]類型
value的值可以一般是掃描包名:
首先我分別創建一個dao,service,controller分別在三個不同包中,注意看下包名,我這爲了方便觀看,將三個類整合到了一起。
package dao;
import org.springframework.stereotype.Repository;
@Repository
public class TestDao {}
/*----------------------------------------------*/
package Controller;
import org.springframework.stereotype.Controller;
@Controller
public class TestController {}
/*----------------------------------------------*/
package service;
import org.springframework.stereotype.Service;
@Service
public class TestService {}
我這掃描Controller、dao,service註解
//配置類==配置文件
@Configuration //告訴spring這是一個配置類
//掃描策略
@ComponentScan(value = {"Controller","dao","service"}) //也可以根目錄掃描的方式,會自動掃描目錄下帶有4個註解的包
public class MainConfig {}
public class AnnoTest {
@SuppressWarnings("resource")
@Test
public void test01(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] definition = applicationContext.getBeanDefinitionNames();
for(String name : definition){
System.out.println("name:"+name);
//在打印的信息中我們可以看到上方標註了@Controller @Service @Repository的類名
}
}
}
excludeFilters:過濾器,定義了過濾規則,相當於<context:component-scan bse-package=""></context:component-scan>內的子標籤<context:exclude-filter type="" expression=""/>主要的過濾規則爲:
FilterType.ANNOTATION:按照註解
FilterType.ASSIGNABLE_TYPE:按照給定的類型
FilterType.ASPECTJ:使用ASPECTJ表達式
FilterType.REGEX:使用正則
FilterType.CUSTOM:使用自定義規則
例如:type爲按照註解類型,value中指定了不被掃描的註解名稱,我們這樣可以在掃描的時候跳過帶有這兩個註解的類。
//配置類==配置文件
@Configuration //告訴spring這是一個配置類
//掃描策略
@ComponentScan(value = {"Controller","dao","service"},excludeFilters ={
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class,Service.class}), //按照註解來過濾
}) //也可以根目錄掃描的方式,會自動掃描目錄下帶有4個註解的包
public class MainConfig {
}
我們查看spring定義註解ComponentScan我們可以找到Filter,我們可以發現spring中默認是註解方式的過濾規則,點開FilterType我們能發現spring定義幾種過濾規則。
includeFilters:與excludeFilters作用相反,掃描時只掃描的包,但是需要注意的是,使用這個的時候需要指定userDefaultFilters = false把默認掃描規則爲false,因爲默認的時true不會生效。
@ComponentScan(value = {"Controller","dao","service"},includeFilters ={
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class,Service.class}), //按照註解來過濾
},useDefaultFilters = false) //也可以根目錄掃描的方式,會自動掃描目錄下帶有4個註解的包
public class MainConfig {
}
FilterType.CUSTOM:自定義掃描規則,這個稍微重要點。
我們需要自定義一個Filter實現TypeFilter並重寫match方法,並根據方法返回的布爾類型爲true或false來判斷是否過濾。
例如:指定Filter類型爲自定義類型,值爲自己定義的一個類
//配置類==配置文件
@Configuration //告訴spring這是一個配置類
//掃描策略
@ComponentScan(value = {"Controller","dao","service"},excludeFilters ={
@ComponentScan.Filter(type = FilterType.CUSTOM,value = {MyFilter.class}) //由自定義的Filter返回的布爾值來過濾
})
public class MainConfig {
}
public class MyFilter implements TypeFilter {
/**
* @param metadataReader 讀取到的當前正在掃描的類的信息
* @param metadataReaderFactory 獲取其他任何類的信息
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//獲取當前類註解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//獲取當前按正在掃描的類的類信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//獲取當前類資源(類的路徑)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("---->"+className);
if(className.contains("er")){
return true;
}
return false;
}
}
public class AnnoTest {
@SuppressWarnings("resource")
@Test
public void test01(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] definition = applicationContext.getBeanDefinitionNames();
for(String name : definition){
System.out.println("name:"+name);
}
}
}
打印信息:
---->Controller.TestController
---->dao.d.TesDao1
---->dao.d1.TesDao2
---->dao.TestDao
---->service.TestService
name:tesDao1
name:tesDao2
name:testDao
我們可以看到掃描的類有5個,但是隻要標註了@Repository的沒有被過濾,@Controller和@Service都被過濾掉了,因爲他們包了"er"。
記錄學習筆記算是強制讓自己學習和鞭策自己,同時也希望能夠幫助有需要的夥伴,對於筆記有什麼錯誤的或者不足的希望大家能幫忙糾正一下。萬分感謝!