title: spring基于注解开发
date: 2019-03-03 10:29:05
tags: spring
spring基于注解开发
一、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
参数来限制扫描的范围。例如
@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环境下加载"bill"这个bean,而在“linux”环境下加载‘’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
类实现Condition接口,在实现方法中来判断环境
public class WindowCondition implements Condition
{
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
{
Environment environment = context.getEnvironment();
//这里可以通过context、metadata参数实现多样的判断条件
if(environment.getProperty("os.name").contains("Windows"))
{
return true;
}
return false;
}
}
5.@import
在配置类上通过@Import
注解也可以加载bean
- 直接指定需要加载的类
@Configuration
@Import(Apple.class)
public class Config {
}
- 通过实现
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 {
}
- 通过实现
ImportBeanDefinitionRegistrar
接口来实现加载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,可以实现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的实际类型,可以发现为Apple,如果需要获取AppleFactory
本身的bean的话,可以在名称前加&,如applicationContext.getBean("&appleFactory");
Object apple = applicationContext.getBean("appleFactory");
System.out.println(apple.getClass());
//打印内容:class com.example.demo.bean.Apple
todo...