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;
}
}
測試:
public static void main(String[] args)
{
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
Person person = applicationContext.getBean("person", Person.class);
System.out.println(person);
}
@Bean 注解默認采用方法名作為bean的名字,也可以指定bean名。
2.@ComponentScan、@Component、@Service等
@ComponentScan(basePackages = "com.tiger")
public class Config
{
}
@Component
public class Person
{
}
@Service
public class PersonService
{
}
測試:
@Test
public void test1()
{
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
Config.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for(String beanName:beanDefinitionNames)
{
System.out.println(beanName);
}
}
結果:
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里的一個字段boolean useDefaultFilters() default true;默認為true,也就是默認會加載指定包下的所有bean,如果只想指定的bean被加載,應設定為false,此時通過includeFilters來指定需要加載的bean才會生效,如下
@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"字符串的類才會被spring容器加載。
3.@Scope、@Lazy
常用的
-
@Scope("singleton")該bean在spring容器中為單例,每次取bean都是同一個,而且該bean在spring容器啟動的時候就會被實例化 -
@Scope("prototype")每次獲取bean都是重新實例化。 -
@Lazy如果bean的作用域為單例,而且不希望在spring容器剛啟動時就被加載,可以用此注解,這樣只有在獲取該bean時才會被實例化。
4.@Conditional
可以通過該注解來決定當前的bean是否應該被加載到spring容器,比如以下的兩個bean,希望在Windows環(huán)境下加載"bill"這個bean,而在“l(fā)inux”環(huán)境下加載‘’linas‘這個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類實現(xiàn)Condition接口,在實現(xiàn)方法中來判斷環(huán)境
public class WindowCondition implements Condition
{
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
{
Environment environment = context.getEnvironment();
//這里可以通過context、metadata參數(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 {
}
- 通過實現(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 {
}
- 通過實現(xiàn)
ImportBeanDefinitionRegistrar接口來實現(xiàn)加載bean,例如如果有名為apple的bean就加載TestControllerbean
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,可以實現(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的實際類型,可以發(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...