zoukankan      html  css  js  c++  java
  • SpringIOC容器的注解使用

    一、@ComponentScan 进行包扫描

    在配置类上写 @CompentScan 注解来进行包扫描 

    @Configuration
    @ComponentScan(basePackages = {"com.yufeng.testcompentscan"})
    public class MainConfig {
    }
    

    1、排除用法; excludeFilters排除标注@Controller注解 和 TestService类

    @Configuration
    @ComponentScan(basePackages = {"com.yufeng.testcompentscan"}, excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {TestService.class})
    })
    public class MainConfig {
    }
    

    2、包含用法 includeFilters; 注意,若使用包含的用法,需要把useDefaultFilters属性设置为falsetrue表示扫描全部的 @Controller @Service @Component @Repository 标注的类) ;

    @ComponentScan.Filter type的类型:

    • FilterType.ANNOTATION:注解形式的,@Controller @Service @Repository @Compent;
    • FilterType.ASSIGNABLE_TYPE:指定类型的,@ComponentScan.Filter(type =FilterType.ASSIGNABLE_TYPE,value = {Test.class});
    • FilterType.ASPECTJ:aspectj类型的(不常用);
    • FilterType.REGEX:正则表达式的 (不常用);
    • FilterType.CUSTOM:自定义的,实现 TypeFilter 接口;

    FilterTyp.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;
        }
    }
    
    @ComponentScan(basePackages = {"com.yufeg.testcompentscan"}, includeFilters = {
            @ComponentScan.Filter(type = FilterType.CUSTOM,value = CustomFilterType.class)
    },useDefaultFilters = false)
    
    注意:excludeFilters 优先级高于 includeFilters

    二、向IOC容器中添加组件的4种方式

    1、@CompentScan + @Controller @Service @Respository @Compent

    2、@Bean 的方式导入组件(适用于导入第三方类的组件);

    3、@Import 导入(注意:导入的组件的id为全类名);
    (1)简单的导入方法
    @Configuration
    @Import(value = {Person.class, Car.class})
    public class MainConfig {
    }
    

    (2)通过 @Import 导入实现 ImportSeletor 接口的类  (导入组件的id为全类名路径

    @Configuration
    @Import(value = {Person.class, Car.class, MyImportSelector.class})
    public class MainConfig {
    }
    
    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{"com.yufeng.testimport.compent.Dog"};
        }
    }
    

    (3)通过@Import 导入 ImportBeanDefinitionRegistrar 导入组件 (可以指定bean的名称

    @Configuration
    @Import(value = {Person.class, Car.class, MyImportSelector.class, MyBeanDefinitionRegister.class})
    public class MainConfig {
    }
    
    public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
            registry.registerBeanDefinition("cat",rootBeanDefinition);
        }
    }
    

    4、通过实现 FactoryBean 接口来实现注册组件;

    public class CarFactoryBean implements FactoryBean<Car> {
    
        @Override
        public Car getObject() throws Exception {
            return new Car();
        }
    
        @Override
        public Class<?> getObjectType() {
            return Car.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    @Configuration
    public class MainConfig {
        @Bean
        public CarFactoryBean carFactoryBean() {
            return new CarFactoryBean();
        }
    }
    public class MainClass {
        public static void main(String[] args) throws Exception {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
            // 获取到 car 对象
            Object bean = ctx.getBean("carFactoryBean");
            System.out.println(bean);
            // 获取到 carFactoryBean 对象
            Object bean2 = ctx.getBean("&carFactoryBean");
            System.out.println(bean2);
        }
    }

    三、Bean的作用域

    1、在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉加载(容器启动实例就创建好了);

    可以使用 @Lazy 指定为懒加载;
    2、指定@Scope为 prototype 表示为多实例的,而且还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是在第一次使用的时候才会创建);
    3、@Scope 指定的作用域方法取值
    • singleton 单实例的(默认);
    • prototype 多实例的;
    • request 同一次请求;
    • session 同一个会话级别;

     四、@Conditional进行条件判断等

    @Conditional 的应用,规则类去实现 Condition 接口;

    1、实现 Condition 接口;

    public class TulingCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            //判断容器中是否有myAspect的组件
            if(context.getBeanFactory().containsBean("myAspect")) {
                return true;
            }
            return false;
        }
    }
    
    2、在配置中增加 @Conditional 注解,并指定其条件的规则;
    public class MainConfig {
        //@Bean
        public MyAspect myAspect() {
            return new MyAspect();
        }
    
        @Bean
        @Conditional(value = MyCondition.class)
        public Car car() {
            return new Car();
        }
    }
    

    五、Bean的初始化方法和销毁方法

    Bean的生命周期:bean的创建 ----> bean 的初始化 ---> bean的销毁;
    1、@Bean 的 initMethod 和 desstoryMethod 方法定义初始化方法

    由容器管理Bean的生命周期,我们可以通过自己指定bean的初始化方法和bean的销毁方法 。

    @Configuration
    public class MyConfig {
        @Bean(initMethod = "init", destroyMethod = "destroy")
        public Car car() {
            return new Car();
        }
    }
    public class Car {
        public Car() {
            System.out.println("Car的构造方法..........");
        }
        // 初始化方法
        public void init() {
            System.out.println("Car的初始化方法......init");
        }
        // 销毁方法
        public void destroy() {
            System.out.println("Car的销毁方法.....destroy");
        }
    }

    单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法。
    多实例bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受IOC容器的管理。

    2、通过JSR250规范 提供的注解 @PostConstruct @ProDestory 标注的方法 。
    @Configuration
    @ComponentScan(basePackages = {"com.yufeng.testbeanlifecycle.my"})
    public class MyConfig {
    }
    
    @Component
    public class Book {
    
        public Book() {
            System.out.println("book 的构造方法");
        }
    
        @PostConstruct
        public void init() {
            System.out.println("book 的PostConstruct标志的方法");
        }
    
        @PreDestroy
        public void destory() {
            System.out.println("book 的PreDestory标注的方法");
        }
    }
    

    3、通过实现 InitializingBean DisposableBean 这两个接口的bean的初始化以及销毁方法;

    @Configuration
    @ComponentScan(basePackages = {"com.yufeng.testbeanlifecycle.my"})
    public class MyConfig {
    }
    
    @Component
    public class Dog implements InitializingBean, DisposableBean {
        public Dog() {
            System.out.println("-- Dog 构造方法");
        }
        // 在Bean初始化的时候执行,可以操作Bean的属性
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("-- Dog 的 afterPropertiesSet");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("-- Dog 的 destroy");
        }
    }
    

    4、通过 SpringBeanPostProcessorbean的后置处理器 会拦截所有bean创建过程;(可以用来操作bean的属性)

    postProcessBeforeInitialization 在init方法之前调用; postProcessAfterInitialization 在init方法之后调用;
    @Configuration
    @ComponentScan(basePackages = {"com.yufeng.testbeanlifecycle.my"})
    public class MyConfig {
    }
    
    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("MyBeanPostProcessor...postProcessBeforeInitialization:"+beanName);
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("MyBeanPostProcessor...postProcessAfterInitialization:"+beanName);
            return bean;
        }
    }
    
    @Component
    public class Dog implements InitializingBean, DisposableBean {
        public Dog() {
            System.out.println("-- Dog 构造方法");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("-- Dog 的 afterPropertiesSet");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("-- Dog 的 destroy");
        }
    }
    

    启动后结果如下:

     六、自动装配

    1、@Autowired 

    配置类:

    @Configuration
    @ComponentScan(basePackages = {"com.yufeng.testautowired.autowired.my"})
    public class MainConfig {
    
        @Bean
        public Car car() {
            return new Car();
        }
    
        @Bean
        public Car car2() {
            return new Car("car2-----noise");
        }
    }
    

    实体类:

    public class Car {
        private String noise;
        public Car() {}
        public Car(String noise) {
            this.noise = noise;
        }
        
        // getter、 setter、toString方法
    }
    

    Service类:

    @Service
    public class MyService {
    
        @Autowired
        private Car car2;
    
        public void aa() {
            System.out.println("--- test: " + car2);
        }
    }
    

    启动类:

    public class MainDemo {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
            MyService myService = (MyService) ctx.getBean("myService");
            myService.aa();
        }
    }
    

    运行结果:--- test: Car{noise='car2-----noise'}

    结论

    (1)@Autowired  首先时按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照 属性名称来进行装配。

    (2)如果我们需要指定特定的组件来进行装配,我们可以通过使用 @Qualifier("car") 来指定装配的组件,或者在配置类上的 @Bean 加上 @Primary注解;

     注意:@Qualifier 优先级高于 @Primary;

    (3)@Autowired 可以标注在方法上、构造方法上、配置类的方法入参上;

    a.  @Qualifier 使用

    @Service
    public class MyService {
    
        @Autowired
        @Qualifier("car")
        private Car car2;
    
        public void aa() {
            System.out.println("--- test: " + car2);
        }
    }
    

    运行结果:--- test: Car{noise='null'}

    b. @Primary 

    @Configuration
    @ComponentScan(basePackages = {"com.tuling.testautowired.autowired.my"})
    public class MainConfig {
    
        @Bean
        public Car car() {
            return new Car();
        }
    
        @Bean
        @Primary
        public Car car2() {
            return new Car("car2-----noise");
        }
    }
    

    2、@Resource (JSR250规范)

    @Resource的作用相当于@Autowired,只不过@Autowired按照 byType自动注入,@Resource默认按照 byName 进行装配。

    @Resource装配顺序:

    • ①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
    • ②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
    • ③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
    • ④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

    3、@InJectJSR330规范),需要导入jar包依赖;

    功能和支持@Primary功能 ,但是没有Require=false的功能;

    @Inject 没有 required 属性,因此在找不到合适的依赖对象时 inject 会失败,而 @Autowired 可以使用 required=false 来允许 null 注入。

    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>

    七、通过@Value +@PropertySource来给组件赋值

     配置类:

    @Configuration
    @PropertySource(value = {"classpath:my.properties"})
    public class MainConfig {
        @Bean
        public Person person() {
            return new Person();
        }
    }
    

    配置文件 my.properties:

    person.lastName=吹雪
    

    实体类:

    public class Person {
    
        @Value("西门")
        private String firstName;
    
        @Value("#{28-2}")
        private Integer age;
    
        @Value("${person.lastName}")
        private String lastName;
    
        // getter 和 setter 的方法
    }
    

    运行结果:Person{firstName='西门', age=26, lastName='吹雪'}

    八、自定义组件需要使用Spring IOC中的Bean,可以通过实现 XXXAware 接口来实现

    实现 ApplicationContextAware 和 BeanNameAware 接口:

    @Component
    public class CustomCompent implements ApplicationContextAware,BeanNameAware {
    
        private ApplicationContext applicationContext;
    
        @Override
        public void setBeanName(String name) {
            System.out.println("current bean name is :【"+name+"】");
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }

    九、通过@Profile注解 来根据环境来激活标识不同的Bean

    @Profile标识在类上,那么只有当前环境匹配,整个配置类才会生效;

    @Profile标识在Bean上 ,那么只有当前环境的Bean才会被激活没有标志为@Profile的 bean 不管在什么环境都可以被激活;

    配置类:

    @Configuration
    @PropertySource(value = {"classpath:ds.properties"})
    public class MainConfig implements EmbeddedValueResolverAware {
    
        @Value("${ds.username}")
        private String userName;
    
        @Value("${ds.password}")
        private String password;
    
        private String jdbcUrl;
    
        private String classDriver;
    
        @Override
        public void setEmbeddedValueResolver(StringValueResolver resolver) {
            this.jdbcUrl = resolver.resolveStringValue("${ds.jdbcUrl}");
            this.classDriver = resolver.resolveStringValue("${ds.classDriver}");
        }
    
        @Bean
        @Profile(value = "test")
        public DataSource testDs() {
            return buliderDataSource(new DruidDataSource());
        }
    
        @Bean
        @Profile(value = "dev")
        public DataSource devDs() {
            return buliderDataSource(new DruidDataSource());
        }
    
        @Bean
        @Profile(value = "prod")
        public DataSource prodDs() {
            return buliderDataSource(new DruidDataSource());
        }
    
        private DataSource buliderDataSource(DruidDataSource dataSource) {
            dataSource.setUsername(userName);
            dataSource.setPassword(password);
            dataSource.setDriverClassName(classDriver);
            dataSource.setUrl(jdbcUrl);
            return dataSource;
        }
    }
    

    配置文件 ds.properties :

    ds.username=root
    ds.password=123456
    ds.jdbcUrl=jdbc:mysql://localhost:3306/test
    ds.classDriver=com.mysql.jdbc.Driver
    

    启动类:

    public class MainClass {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
            ctx.getEnvironment().setActiveProfiles("test","dev");
            ctx.register(MainConfig.class);
            ctx.refresh();
    
            for(String beanName: ctx.getBeanDefinitionNames()) {
                System.out.println("容器中的BeanName:"+beanName);
            }
        }
    }
    

    结果:

  • 相关阅读:
    Android 横屏启动activity,点击屏幕的单击、双击
    实现Android简单动画旋转案例
    当时遇到的主要难点在于TextView的内容不会刷新改变值,今天终于通过Timer和Handler实现了,分享给大家
    如何在Android当中显示网络图片
    Android的MediaRecorder架构介绍
    理解Android系统的进程间通信原理RPC机制
    Android开发WeatherForecast程序
    Android 如何导入已有的外部数据库
    百度地图API 源码
    Android TelephonyManager类
  • 原文地址:https://www.cnblogs.com/yufeng218/p/14264199.html
Copyright © 2011-2022 走看看