title: spring基于注解開發(fā)
date: 2019-03-03 10:29:05
tags: spring
spring基于注解開發(fā)
一氓辣、bean的加載
1.@Configuration,@Bean
@Configuration
public class Config
{
@Bean("person")
public Person personA()
{
Person a =new Person(10,"jerry");
return a;
}
}
測(cè)試:
public static void main(String[] args)
{
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
Person person = applicationContext.getBean("person", Person.class);
System.out.println(person);
}
@Bean 注解默認(rèn)采用方法名作為bean的名字袱蚓,也可以指定bean名钞啸。
2.@ComponentScan、@Component、@Service等
@ComponentScan(basePackages = "com.tiger")
public class Config
{
}
@Component
public class Person
{
}
@Service
public class PersonService
{
}
測(cè)試:
@Test
public void test1()
{
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
Config.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for(String beanName:beanDefinitionNames)
{
System.out.println(beanName);
}
}
結(jié)果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
config
person
personDao
personService
可以通過excludeFilters
參數(shù)來限制掃描的范圍体斩。例如
@ComponentScan(basePackages = "com.tiger", excludeFilters = { @Filter(type = FilterType.ANNOTATION,classes = {
Controller.class}) })
值得一提的是@ComponentScan
里的一個(gè)字段boolean useDefaultFilters() default true;
默認(rèn)為true梭稚,也就是默認(rèn)會(huì)加載指定包下的所有bean,如果只想指定的bean被加載絮吵,應(yīng)設(shè)定為false
弧烤,此時(shí)通過includeFilters
來指定需要加載的bean才會(huì)生效,如下
@ComponentScan(basePackages = "com.tiger", includeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = { Service.class }),
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { Person.class }) },useDefaultFilters = false)
public class Config
{
}
還可以定制化Filter來過濾需要加載的bean蹬敲,如下
public class MyFilter implements TypeFilter
{
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException
{
ClassMetadata classMetadata = metadataReader.getClassMetadata();
String className = classMetadata.getClassName();
if(className.contains("Dao"))
{
return true;
}
return false;
}
}
@ComponentScan(basePackages = "com.tiger", includeFilters = {
@Filter(type = FilterType.CUSTOM,classes = MyFilter.class)
},useDefaultFilters = false)
public class Config
{
}
這樣包含"Dao"字符串的類才會(huì)被spring容器加載扼褪。
3.@Scope、@Lazy
常用的
-
@Scope("singleton")
該bean在spring容器中為單例粱栖,每次取bean都是同一個(gè),而且該bean在spring容器啟動(dòng)的時(shí)候就會(huì)被實(shí)例化 -
@Scope("prototype")
每次獲取bean都是重新實(shí)例化脏毯。 -
@Lazy
如果bean的作用域?yàn)閱卫志浚也幌M趕pring容器剛啟動(dòng)時(shí)就被加載,可以用此注解食店,這樣只有在獲取該bean時(shí)才會(huì)被實(shí)例化渣淤。
4.@Conditional
可以通過該注解來決定當(dāng)前的bean是否應(yīng)該被加載到spring容器,比如以下的兩個(gè)bean吉嫩,希望在Windows環(huán)境下加載"bill"這個(gè)bean价认,而在“l(fā)inux”環(huán)境下加載‘’linas‘這個(gè)bean,代碼如下
@Conditional(WindowCondition.class)
@Bean("bill")
public Person person()
{
return new Person(19,"bill Gates");
}
@Conditional(LinuxCondition.class)
@Bean("linas")
public Person person2()
{
return new Person(20,"linas");
}
WindowCondition
類實(shí)現(xiàn)Condition接口自娩,在實(shí)現(xiàn)方法中來判斷環(huán)境
public class WindowCondition implements Condition
{
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
{
Environment environment = context.getEnvironment();
//這里可以通過context用踩、metadata參數(shù)實(shí)現(xiàn)多樣的判斷條件
if(environment.getProperty("os.name").contains("Windows"))
{
return true;
}
return false;
}
}
5.@import
在配置類上通過@Import
注解也可以加載bean
- 直接指定需要加載的類
@Configuration
@Import(Apple.class)
public class Config {
}
- 通過實(shí)現(xiàn)
ImportSelector
接口,來指定需要加載的bean忙迁,如下
public class MySelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.example.demo.bean.Apple", "com.example.demo.controller.TestController"};
}
}
@Configuration
@Import(MySelector.class)
public class Config {
}
- 通過實(shí)現(xiàn)
ImportBeanDefinitionRegistrar
接口來實(shí)現(xiàn)加載bean脐彩,例如如果有名為apple
的bean就加載TestController
bean
public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
String[] beanDefinitionNames = registry.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
if (beanName.contains("apple")) {
RootBeanDefinition testConDef = new RootBeanDefinition(TestController.class);
registry.registerBeanDefinition("testController",testConDef);
}
}
}
}
@Configuration
@Import(MyImportBeanDefinitionRegister.class)
public class Config {
@Bean("apple")
public Apple apple() {
return new Apple();
}
}
6.通過工廠類來裝配bean,可以實(shí)現(xiàn)FactoryBean
接口來注入bean
@Component
public class AppleFactory implements FactoryBean<Apple> {
@Override
public Apple getObject() throws Exception {
return new Apple();
}
@Override
public Class<?> getObjectType() {
return Apple.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
該bean在spring容器里的名稱為appleFactory
姊扔,但是通過獲取該bean的實(shí)際類型惠奸,可以發(fā)現(xiàn)為Apple,如果需要獲取AppleFactory
本身的bean的話恰梢,可以在名稱前加&,如applicationContext.getBean("&appleFactory");
Object apple = applicationContext.getBean("appleFactory");
System.out.println(apple.getClass());
//打印內(nèi)容:class com.example.demo.bean.Apple
todo...