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);
        }
    }
}

结果:

原文地址:https://www.cnblogs.com/yufeng218/p/14264199.html