Spring IOC 容器底层注解使用
在前文我们已经对于Spring架构中常用的模块已经有了整体的认知,详情可参考:
本文我们来详细介绍IOC容器中常用的注解的配置和使用,强烈建议收藏,以后再遇到某个注解的参数配置不清晰时,完全可省去百度的多余时间,直接查看本文,快速解答你的疑惑!
一、Bean的定义
1.1 xml配置文件的形式
①:基于xml的形式定义Bean的信息
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> //定义一个Bean的信息 <bean id="car" class="com.taoren.compent.Car"></bean> </beans>
去容器中读取Bean
public static void main( String[] args ) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); System.out.println(ctx.getBean("person")); }
1.2 配置类的形式
②:基于读取配置类的形式定义Bean信息
@Configuration public class MainConfig { @Bean public Person person(){ return new Person(); } }
注意: 通过@Bean
的形式是使用的话, bean的默认名称是方法名
- 若@Bean(value=“bean的名称”),那么bean的名称是指定的去容器中读取Bean的信息(传入配置类)
public static void main( String[] args ) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class); System.out.println(ctx.getBean("person")); }
二、@CompentScan注解进行包扫描
@Configuration @ComponentScan(basePackages = {"com.TaoRen.testcompentscan"}) public class MainConfig { }
2.1 排除用法 excludeFilters
@Configuration @ComponentScan(basePackages = {"com.taoren.testcompentscan"},excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {TaoRenService.class}) }) public class MainConfig { }
2.2 包含用法 includeFilters
注意,若使用包含的用法,需要把useDefaultFilters属性设置为false(true表示扫描全部的)
@Configuration @ComponentScan(basePackages = {"com.taoren.testcompentscan"},includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class}) },useDefaultFilters = false) public class MainConfig { }
2.3 @ComponentScan.Filter type的类型
- a)注解形式的FilterType.ANNOTATION
@Controller @Service @Repository @Component
- b)指定类型的 FilterType.ASSIGNABLE_TYPE
@ComponentScan.Filter(type =FilterType.ASSIGNABLE_TYPE,value = {TaoRenService.class})
- c)aspectj类型的 FilterType.ASPECTJ(不常用)
- d)正则表达式的 FilterType.REGEX(不常用)
- e)自定义的 FilterType.CUSTOM:
public enum FilterType { //注解形式 比如@Controller @Service @Repository @Compent ANNOTATION, //指定的类型 ASSIGNABLE_TYPE, //aspectJ形式的 ASPECTJ, //正则表达式的 REGEX, //自定义的 CUSTOM }
FilterType.CUSTOM 自定义类型如何使用
public class TaoRenFilterType implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, Metadata ReaderFactory metadataReaderFactory) throws IOException { //获取当前类的注解源信息 AnnotationMetadata annotationMetadata = metadataReader.getA>nnotationMetadata(); //获取当前类的class的源信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //获取当前类的资源信息 Resource resource = metadataReader.getResource(); if(classMetadata.getClassName().contains("dao")) { return true; } return false; } } @ComponentScan(basePackages = {"com.TaoRen.testcompentsca>n"},includeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM,value = TaoRenFilterType.class) },useDefaultFilters = false) public class MainConfig { }
三、配置Bean的作用域对象
3.1 @Scope的默认使用
在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉加载(容器启动实例就创建好了)
@Bean public Person person() { return new Person(); }
3.2 指定@Scope为 prototype 表示为多实例
该模式还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是在第一次使用的时候才会创建)
@Bean @Scope(value = "prototype") public Person person() { return new Person(); }
3.3 @Scope指定的作用域方法取值
- a) singleton 单实例的(默认)
- b) prototype 多实例的
- c) request 同一次请求
- d) session 同一个会话级别
3.4 Bean的懒加载@Lazy
主要针对单实例的bean 容器启动的时候,不创建对象,在第一次使用的时候才会创建该对象
@Bean @Lazy public Person person() { return new Person(); }
四、 @Conditional进行条件判断等.
场景,有二个组件TaoRenAspect 和TaoRenLog ,我的TaoRenLog组件是依赖于TaoRenAspect的组件
应用:自己创建一个TaoRenCondition的类 实现Condition接口 public class TaoRenCondition implements Condition { /** * * @param context * @param metadata * @return */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //判断容器中是否有TaoRenAspect的组件 if(context.getBeanFactory().containsBean("TaoRenAspect")) { return true; } return false; } } public class MainConfig { @Bean public TaoRenAspect taorenAspect() { return new TaoRengAspect(); } //当切 容器中有taorenAspect的组件,那么taorenLog才会被实例化. @Bean @Conditional(value = TaoRenCondition.class) public TaoRenLog taorenLog() { return new TaoRenLog(); } }
五、往IOC 容器中添加组件的方式
5.1 通过@CompentScan +@Controller @Service @Respository @component
适用场景: 针对我们自己写的组件可以通过该方式来进行加载到容器中。
- ②:通过@Bean的方式来导入组件(适用于导入第三方组件的类)
- ③:通过@Import来导入组件 (导入组件的id为全类名路径
@Configuration @Import(value = {Person.class, Car.class}) public class MainConfig { }
5.2 通过@Import 的ImportSeletor类实现组件的导入 (导入组件的id为全类名路径)
public class TaoRenImportSelector implements ImportSelector { /可以获取导入类的注解信息 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.TaoRen.testimport.compent.Dog"}; } } @Configuration @Import(value = {Person.class, Car.class, TaoRenImportSelector.class}) public class MainConfig { }
5.3 通过@Import的 ImportBeanDefinitionRegister导入组件 (可以指定bean的名称)
public class TaoRenBeanDefinitionRegister implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //创建一个bean定义对象 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class); //把bean定义对象导入到容器中 registry.registerBeanDefinition("cat",rootBeanDefinition); } } @Configuration //@Import(value = {Person.class, Car.class}) //@Import(value = {Person.class, Car.class, TaoRenImportSelector.class}) @Import(value = {Person.class, Car.class, TaoRenImportSelector.class, TaoRenBeanDefinitionRegister.class}) public class MainConfig { }
5.4 通过实现FacotryBean接口来实现注册组件
public class CarFactoryBean implements FactoryBean<Car> { /返回bean的对象 @Override public Car getObject() throws Exception { return new Car(); } /返回bean的类型 @Override public Class<?> getObjectType() { return Car.class; } /是否为单利 @Override public boolean isSingleton() { return true; } }