本文將主要針對Spring註解,講解在組件註冊過程會用到一些註解,對於小編本身是基礎的回顧和鞏固,也希望能幫助到需要的朋友,講解偏頗之處,還請各位大神指正,小編不勝感激。
1、在容器中註冊組件
1.1@Configuration
標註在類上,告訴spring這是一個配置類,代替spring的xml配置文件中<beans>。作用:配置spring容器(應用上下文)
優點
1、使用純Java代碼,不在需要xml
2、在配置中可以享受OO帶來的好處
3、類型安全對重構也能提供良好的支持
4、依舊能享受到所有SpringIOC容器提供的功能
1.2@Bean
標註在方法上,相當於spring的xml配置文件中<bean>。作用:註冊bean對象bean類
注意:
1、@Bean註解在返回實例的方法上,如果沒有通過@Bean指定bean的名稱,則默認與標註的方法名相同
2、@Bean註解默認作用域爲單例singleton作用域,但是可以通過@Scope("prototype")設置爲原型作用域(ps:@Scope下文有講解)
3、@Bean的作用註冊對象,也可以使用@Component,@Controller,@Service,@Repository等註解註冊Bean,但是需要配置@ComponentScan註解進行自動掃描
2、掃描組件
2.1@ComponentScan(value)
標註在類上,相當於spring的xml配置文件中 <context:component-scan base-package="**"/>。作用:在定義掃描的路徑從中找到標識了需要裝配的類自動裝配到spring的容器中
2.2通過@ComponentScan指定掃描規則
標註在@ComponentScan後面括號中,作用按照指定規則向spring容器中自動裝配bean
excludeFilters = Filter[] :指定掃描的時候按照什麼規則排除那些組件,類似於spring中xml配置文件中
<context:component-scan base-package="**">
<context:exclude-filter type="**" expression="**" />
</context:component-scan>
註解的使用方式
@ComponentScan(value="**",
excludeFilters = {@Filter(type=**,classes={**})}
includeFilters = Filter[] :指定掃描的時候只需要包含哪些組件,類似於spring中xml配置文件中
<!--use-default-filters="false" 使用只包含哪些組件,需要禁用默認的裝配規則-->
<context:component-scan base-package="**" use-default-filters="false">
<context:include-filter type="**" expression="**"
</context:component-scan>
註解的使用方式
@ComponentScan(value="**",excludeFilters = {@Filter(type=**,classes={**})},useDefaultFilters = false)}
@Filter包含的過濾類型
FilterType.ANNOTATION:按照註解
FilterType.ASSIGNABLE_TYPE:按照給定的類型;
FilterType.ASPECTJ:使用ASPECTJ表達式
FilterType.REGEX:使用正則指定
FilterType.CUSTOM:使用自定義規則
當使用自定義規則的時候即@Filter=FilterType.CUSTOM,自定義的類需要實現TypeFilter接口,然後按自己的需要重寫過濾規則
Demo,過濾類名中包含er的類
import java.io.IOException;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
public class MyTypeFilter implements TypeFilter {
/**
* metadataReader:讀取到的當前正在掃描的類的信息
* metadataReaderFactory:可以獲取到其他任何類信息的
*/
@Override
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();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("er")){
return true;
}
return false;
}
}
//只裝配類名中包含er的類
@ComponentScan(value="**",
excludeFilters = {@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})},
useDefaultFilters = false)
2.3@ComponentScans,裝配多個@ComponentScan裝配規則
在Java8以前不允許在一個類上定義兩個相同的註解,可以使用@ComponentScans,裝配多個@ComponentScan裝配規則
@ComponentScans(
value = {@ComponentScan(value="**",
excludeFilters ={@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})},useDefaultFilters = false)}
)
3、設置組件作用域
3.1@Scope(value)
標註類上或者裝載類的方法上,spring容器中bean默認是單例的,但是可以通過@Scope調整作用域,相當於spring中xml配置文件中的
<bean class="**" scope="**">
註解使用方式
@Service("allusersService")
@Scope("prototype")
public class AllusersServiceImpl{}
作用域
prototype:多實例的:ioc容器啓動並不會去調用方法創建對象放在容器中。
每次獲取的時候纔會調用方法創建對象;
singleton:單實例的(默認值):ioc容器啓動會調用方法創建對象放到ioc容器中。
以後每次獲取就是直接從容器(map.get())中拿,
request:同一次請求創建一個實例
session:同一個session創建一個實例
4、設置組件加載方式
4.1@Lazy懶加載
單實例bean:默認在容器啓動的時候創建對象;
懶加載:容器啓動不創建對象。第一次使用(獲取)Bean創建對象,並初始化;
標註類上或者裝載類的方法上,當第一次使用獲取Bean才創建對象並初始化,相當spring中xml配置文件中
//默認爲false,即立即加載,設置爲true則表示延遲加載
<bean class="***" lazy-init="true">
註解使用方式,延遲裝載
@Service("allusersService")
@Lazy
public class AllusersServiceImpl
5、按條件註冊bean
5.1@Conditional({Condition})
按照一定的條件進行判斷,滿足條件給容器中註冊bean
在spring4中引入,用到帶有@Bean註解的方法上,如果給定的條件計算結果爲true,則會創建這個bean,否則這個bean就會被忽略。
條件化的創建bean,例如判斷環境是爲linux,如果是則註冊
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}
作爲條件的bean,在實現的時候需要實現spring提供的Condition接口
//判斷是否linux系統
public class LinuxCondition implements Condition {
/**
* ConditionContext:判斷條件能使用的上下文(環境)
* AnnotatedTypeMetadata:註釋信息
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1、能獲取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、獲取類加載器
ClassLoader classLoader = context.getClassLoader();
//3、獲取當前環境信息
Environment environment = context.getEnvironment();
//4、獲取到bean定義的註冊類
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
//可以判斷容器中的bean註冊情況,也可以給容器中註冊bean
boolean definition = registry.containsBeanDefinition("person");
if(property.contains("linux")){
return true;
}
return false;
}
}
Spring中@Profile註解根據環境註冊bean,本質上也是利用@Conditional註解實現
6、給容器中導入組件
6.1@Import
@Import導入組件,id默認是組件的全類名,相對於@Bean是一種更快捷的方式
@Configuration
//@Import導入組件,id默認是組件的全類名
@Import({Color.class,Red.class})
public class MainConfig{}
6.2@ImportSelector
返回需要導入的組件全類名數組
自定義的類需要使用@Import註解導入
自定義實現ImportSelector接口的方法
//自定義邏輯返回需要導入的組件
public class MyImportSelector implements ImportSelector {
//返回值,就是到導入到容器中的組件全類名
//AnnotationMetadata:當前標註@Import註解的類的所有註解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//importingClassMetadata
//方法不要返回null值
return new String[]{"com.jia.bean.Blue","com.jia.bean.Yellow"};
}
}
@Configuration
@Import({MyImportSelector.class})
public class MainConfig{}
6.3@ImportBeanDefinitionRegistrar
手動註冊bean到容器中,自定義邏輯實現bean的註冊
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata:當前類的註解信息
* BeanDefinitionRegistry:BeanDefinition註冊類;
* 把所有需要添加到容器中的bean;調用
* BeanDefinitionRegistry.registerBeanDefinition手工註冊進來
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("com.jia.bean.Red");
boolean definition2 = registry.containsBeanDefinition("com.jia.bean.Blue");
if(definition && definition2){
//指定Bean定義信息;(Bean的類型,Bean。。。)
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
//註冊一個Bean,指定bean名
registry.registerBeanDefinition("rainBow", beanDefinition);
}
}
}
@Configuration
@Import({MyImportBeanDefinitionRegistrar.class})
public class MainConfig{}
7、使用FactoryBean容器註冊組件
創建一個spring定義的FactoryBean
import org.springframework.beans.factory.FactoryBean;
//創建一個Spring定義的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一個Color對象,這個對象會添加到容器中
@Override
public Color getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//是單例?
//true:這個bean是單實例,在容器中保存一份
//false:多實例,每次獲取都會創建一個新的bean;
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
1)、默認獲取到的是工廠bean調用getObject創建的對象2)、要獲取工廠Bean本身,我們需要給id前面加一個&
&colorFactoryBean
//工廠Bean獲取的是調用getObject創建的對象
Object bean2 = applicationContext.getBean("colorFactoryBean");
Object bean3 = applicationContext.getBean("colorFactoryBean");
System.out.println("bean的類型:"+bean2.getClass());
System.out.println(bean2 == bean3);
Object bean4 = applicationContext.getBean("&colorFactoryBean");
System.out.println(bean4.getClass());
8、加載spring的應用上下文
AnnotationConfigApplicationContext實現基於Java的配置類加載spring的應用上下文。避免使用application.xml進行配置,相比xml配置,更加便捷。
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
管理註解Bean定義的容器有兩個:
AnnotationConfigApplicationContext和 AnnotationConfigWebApplicationContex。這兩個類是專門處理Spring註解方式配置的容器,直接依賴於註解作爲容器配置信息來源的IoC容器。
AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的web版本,兩者的用法以及對註解的處理方式幾乎沒有什麼差別,在後續的文章小編會進行更加詳細的講解。
總結
給容器中註冊組件:
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
5、使用AnnotationConfigApplicationContext使用配置文件加載spring應用上下文。