Spring IOC容器底层常见注解使用
一、说明
拥抱Springboot,基于各种读取配置类的形式,了解常见IOC底层注解实用。
二、注解详解demo
2.1、配置定义bean
@Configuration public class MainConfig { /** * 注意,当 @Bean 没有指定value或者name的时候,默认的beanName为方法名。 */ @Bean public Person person2(){ return new Person(); } }
去容器中读取bean
public class MainTest { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); System.out.println(context.getBean(Person.class)); System.out.println(context.getBean("person2")); } }
2.2、配置类的@ComponentScan注解扫描
@Configuration //@ComponentScan(basePackages = {"com.cfang.ioc.compantscan"}) @ComponentScan(basePackages = {"com.cfang.ioc.compantscan"},excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class}), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {UserService.class}), @ComponentScan.Filter(type = FilterType.CUSTOM, value = {CustomFilterType.class}) }) public class MainConfig { }
basePackages :配置基本扫描的包路径
excludeFilters :配置排除扫描的规则,ANNOTATION-基于注解、ASSIGNABLE_TYPE-指定类型、CUSTOM-自定义规则
public class CustomFilterType implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //当前类的注解源信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //当前类class源信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //当前类资源信息 Resource resource = metadataReader.getResource(); System.out.println("类的路径:"+classMetadata.getClassName()); if(classMetadata.getClassName().contains("dao")){ return true; } return false; } }
includeFilters :配置扫描的包含规则。其中Filter配置去上面没有差别,但是注意,必须设置 useDefaultFilters = false ,否则默认是true,扫描全路径。
includeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {UserWoker.class}) },useDefaultFilters = false
2.3、Bean的作用域
2.3.1、默认,在不指定@Scope的情况下,bean是单例的,并且是饿汉式加载,即容器启动的时候,就创建实例。
@Configuration public class MainConfig { @Bean public Person person(){ return new Person(); } }
2.3.2、指定@Scope为 prototype 表示多实例,懒汉式加载,即容器启动的时候不会创建实例,在第一次使用的时候才会去创建。
@Configuration public class MainConfig { /** * Scope 配置bean作用域,默认单例模式: * prototype - 多例模式,并且是懒汉式加载,在IOC容器启动的时候,不会创建对象,在第一次使用的时候才去创建 * singleton - 单例模式,默认饿汉式加载,在IOC启动的时候就创建对象 */ @Bean @Scope(scopeName = "prototype") public Person initPerson(){ return new Person(); } }
2.3.3、@Scope 取值:singleton-单例(默认)、prototype-多实例、request-同一个请求、session-同一个会话
2.4、懒加载
懒加载@Lazy主要针对的是单例bean,容器启动的时候,不创建对象,第一次使用的时候才去创建。
@Configuration public class MainConfig { /** * Lazy 配置bean时候懒加载,与 Scope.singleton单例来配合上使用,容器启动的时候不创建对象,第一次使用的时候才去创建对象 */ @Bean @Lazy public Person initPerson(){ return new Person(); } }
2.5、@Conditional条件判断
存在某个组件或者不存在某个组件的时候,才去加载或者不加载bean。Springboot体系中,大量使用到的机制,通常如 @ConditionalOnBean、@ConditionalOnClass 等。
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { if(null != context.getBeanFactory().getBean(UserLog.class)){ return true; } return false; } }
@Configuration public class MainConfig { // @Bean("userLog") public UserLog initUserLog(){ return new UserLog(); } /** * 当容器中有 userLog 组件的时候,才去实例化当前bean */ @Bean @Conditional(value = {Userconditional.class}) // @ConditionalOnBean(value = {UserLog.class}) public UserAspect initUseraspect(){ return new UserAspect(); } }
2.6、IOC容器中添加组件的方法
2.6.1、@ComponentScan + @Contoller @Service @Respository @Component, 自己写的组件,可以通过此种方式导入
2.6.2、@Bean导入组件,适用于第三方组件的类
2.6.3、@Import导入组件,导入的组件id为类名全路径。
@Configuration @Import(value = {Person.class, Car.class, DogImportSelector.class, CatBeanDefiniitionRegister.class}) public class MainConfig { } public class DogImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.cfang.ioc.tImport.Dog"}; } } public class CatBeanDefiniitionRegister implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //创建bean定义对象 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(); rootBeanDefinition.setBeanClass(Cat.class); //bean定义对象注册到容器中,并设置beanName registry.registerBeanDefinition("cat2", rootBeanDefinition); } }
2.6.4、通过FactoryBean注册组件
@Configuration public class MainConfig { @Bean("personFactoryBean") public PersonFactoryBean initBean(){ return new PersonFactoryBean(); } } public class PersonFactoryBean implements FactoryBean<Person> { /** * 返回bean对象 */ @Override public Person getObject() throws Exception { return new Person(); } /** * 设置bean类型 */ @Override public Class<?> getObjectType() { return Person.class; } /** * 是否单例 */ @Override public boolean isSingleton() { return false; } }
2.7、Bean的初始化和销毁方法
2.7.1、生命周期
bean实例化创建 -----> 初始化 -------> use -------->销毁方法。
可通过指定bean的初始化init 和销毁destroy方法
@Configuration @ComponentScan(value = {"com.cfang.ioc.lifecycle"}) public class MainConfig { @Bean(initMethod = "init", destroyMethod = "destroy") public Car car(){ return new Car(); } }
单例bean,容器启动的是,bean就创建了,容器关闭的时候,也会调用对应的销毁bean方法。
多例bean,容器启动的是,不创建,第一次使用的时候去创建,bean的销毁也不受IOC容器管理。
2.7.2、实现 InitializingBean, DisposableBean
@Component public class Book implements InitializingBean, DisposableBean { public Book(){ System.out.println("Book构造方法..."); } @Override public void destroy() throws Exception { System.out.println("DisposableBean.destory...."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("InitializingBean.afterPropertiesSet...."); } }
2.7.3、@PostConstruct、@PreDestroy注解
@Component public class Person { public Person(){ System.out.println("Person构造方法..."); } @PostConstruct public void init(){ System.out.println("Person PostConstruct..."); } @PreDestroy public void destroy(){ System.out.println("Person destroy..."); } }
2.7.4、实现 BeanPostProcessor,bean后置处理器,可拦截bean创建过程
postProcessBeforeInitialization - 在 init 方法之前调用
postProcessAfterInitialization - 在 init 方法之后调用
@Component public class TBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("TBeanPostProcessor.postProcessBeforeInitialization ..." + beanName); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("TBeanPostProcessor.postProcessAfterInitialization ..." + beanName); return bean; } }
2.8、属性主键赋值 @Value + @PropertySource
public class Person { @Value("商业") private String name; @Value("#{28-8}") private Integer year; @Value("${name}") private String lname; @Override public String toString() { return name + lname + year; } } @Configuration @PropertySource(value = {"classpath:bean.properties"}) public class MainConfig { @Bean("person") public Person initBean(){ return new Person(); } }