Spring注解版学习笔记——组件添加
1、AnnotationConfigApplicationContext
1 public class MainTest { 2 3 public static void main(String[] args) { 4 // ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); 5 // Person bean = (Person) applicationContext.getBean("person"); 6 // System.out.println(bean); 7 8 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); 9 Person bean = applicationContext.getBean(Person.class); 10 System.out.println(bean); 11 12 String[] namesForType = applicationContext.getBeanNamesForType(Person.class); 13 for (String name : namesForType) { 14 System.out.println(name); 15 } 16 17 } 18 19 }
2、@ComponentScan(s)
包扫描注解
1 //配置类==配置文件 2 @Configuration //告诉Spring这是一个配置类 3 4 @ComponentScans( 5 value = { 6 @ComponentScan(value="com.atguigu",includeFilters = { 7 /* @Filter(type=FilterType.ANNOTATION,classes={Controller.class}), 8 @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),*/ 9 @Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class}) 10 },useDefaultFilters = false) 11 } 12 ) 13 //@ComponentScan value:指定要扫描的包 14 //excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件 15 //includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件 16 //FilterType.ANNOTATION:按照注解 17 //FilterType.ASSIGNABLE_TYPE:按照给定的类型; 18 //FilterType.ASPECTJ:使用ASPECTJ表达式 19 //FilterType.REGEX:使用正则指定 20 //FilterType.CUSTOM:使用自定义规则 21 public class MainConfig { 22 23 //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id 24 @Bean("person") 25 public Person person01(){ 26 return new Person("lisi", 20); 27 } 28 29 }
重点关注自定义规则: FilterType.CUSTOM,对应的自定义规则类需要实现接口 TypeFilter ,Spring根据具体实现判断过滤规则
1 public class MyTypeFilter implements TypeFilter { 2 3 /** 4 * metadataReader:读取到的当前正在扫描的类的信息 5 * metadataReaderFactory:可以获取到其他任何类信息的 6 */ 7 @Override 8 public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) 9 throws IOException { 10 // TODO Auto-generated method stub 11 //获取当前类注解的信息 12 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); 13 //获取当前正在扫描的类的类信息 14 ClassMetadata classMetadata = metadataReader.getClassMetadata(); 15 //获取当前类资源(类的路径) 16 Resource resource = metadataReader.getResource(); 17 18 String className = classMetadata.getClassName(); 19 System.out.println("--->"+className); 20 if(className.contains("er")){ 21 return true; 22 } 23 return false; 24 } 25 26 }
MetadataReader 类似于一个数据聚合期,同样可以类比到其他 xxxMetadata
1 public interface MetadataReader { 2 Resource getResource(); 3 4 ClassMetadata getClassMetadata(); 5 6 AnnotationMetadata getAnnotationMetadata(); 7 }
3、@Bean
1 @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 public @interface Bean { 5 @AliasFor("name") 6 String[] value() default {}; 7 8 @AliasFor("value") 9 String[] name() default {}; 10 11 Autowire autowire() default Autowire.NO; 12 13 String initMethod() default ""; 14 15 String destroyMethod() default "(inferred)"; 16 }
initMethod、destroyMethod 指定对应的初始化,销毁方法。与之对应的JSR250标准是:@PostConstruct,@PreDestroy
1 @Component 2 public class Dog implements ApplicationContextAware { 3 4 //@Autowired 5 private ApplicationContext applicationContext; 6 7 public Dog(){ 8 System.out.println("dog constructor..."); 9 } 10 11 //对象创建并赋值之后调用 12 @PostConstruct 13 public void init(){ 14 System.out.println("Dog....@PostConstruct..."); 15 } 16 17 //容器移除对象之前 18 @PreDestroy 19 public void detory(){ 20 System.out.println("Dog....@PreDestroy..."); 21 } 22 23 @Override 24 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 25 // TODO Auto-generated method stub 26 this.applicationContext = applicationContext; 27 } 28 29 30 31 32 }
4、@Configuration
既有将自己的类加入容器,又可以在类中使用@Bean,添加其他的bean到容器中
5、@Component、@Service、@Controller、@Repository
6、@Conditional
@Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean。Condition为一个接口
1 public interface Condition { 2 boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); 3 }
一个Condition实现类举例,判断是否为linux环境:
1 //判断是否linux系统 2 public class LinuxCondition implements Condition { 3 4 /** 5 * ConditionContext:判断条件能使用的上下文(环境) 6 * AnnotatedTypeMetadata:注释信息 7 */ 8 @Override 9 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 10 // TODO是否linux系统 11 //1、能获取到ioc使用的beanfactory 12 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); 13 //2、获取类加载器 14 ClassLoader classLoader = context.getClassLoader(); 15 //3、获取当前环境信息 16 Environment environment = context.getEnvironment(); 17 //4、获取到bean定义的注册类 18 BeanDefinitionRegistry registry = context.getRegistry(); 19 20 String property = environment.getProperty("os.name"); 21 22 //可以判断容器中的bean注册情况,也可以给容器中注册bean 23 boolean definition = registry.containsBeanDefinition("person"); 24 if(property.contains("linux")){ 25 return true; 26 } 27 28 return false; 29 } 30 31 }
7、@Primary
@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
8、@Lazy
单实例bean:默认在容器启动的时候创建对象;懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;- prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象;
- singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿,
- request:同一次请求创建一个实例
- session:同一个session创建一个实例
10、@Import 快速给容器中导入组件
- @Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
- ImportSelector:返回需要导入的组件的全类名数组;
- ImportBeanDefinitionRegistrar:手动注册bean到容器中
1 //自定义逻辑返回需要导入的组件 2 public class MyImportSelector implements ImportSelector { 3 4 //返回值,就是到导入到容器中的组件全类名 5 //AnnotationMetadata:当前标注@Import注解的类的所有注解信息 6 @Override 7 public String[] selectImports(AnnotationMetadata importingClassMetadata) { 8 // TODO Auto-generated method stub 9 //importingClassMetadata 10 //方法不要返回null值 11 return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"}; 12 } 13 14 }
1 public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { 2 3 /** 4 * AnnotationMetadata:当前类的注解信息 5 * BeanDefinitionRegistry:BeanDefinition注册类; 6 * 把所有需要添加到容器中的bean;调用 7 * BeanDefinitionRegistry.registerBeanDefinition手工注册进来 8 */ 9 @Override 10 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 11 12 boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red"); 13 boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue"); 14 if(definition && definition2){ 15 //指定Bean定义信息;(Bean的类型,Bean。。。) 16 RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); 17 //注册一个Bean,指定bean名 18 registry.registerBeanDefinition("rainBow", beanDefinition); 19 } 20 } 21 22 }
11、FactoryBean 工厂模式
要点在于:(1)、实现接口 FactoryBean<T>
1 public interface FactoryBean<T> { 2 T getObject() throws Exception; 3 4 Class<?> getObjectType(); 5 6 boolean isSingleton(); 7 }
(2)、ApplicationContext.getBean() 中传入 FactoryBean<T>的实现类(<? implements FactoryBean<T>>)得到的是 FactoryBean<T>.getObject()值。&beanName获取Factory本身
//创建一个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; } } public class IOCTest { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); @Test public void testImport(){ printBeans(applicationContext); Blue bean = applicationContext.getBean(Blue.class); System.out.println(bean); //工厂Bean获取的是调用getObject创建的对象 Object bean2 = applicationContext.getBean("colorFactoryBean"); // bean2为Color类型 Object bean3 = applicationContext.getBean("colorFactoryBean"); System.out.println("bean的类型:"+bean2.getClass()); System.out.println(bean2 == bean3); Object bean4 = applicationContext.getBean("&colorFactoryBean"); //bean4为ColorFactoryBean 类型 System.out.println(bean4.getClass()); } }