03-SpringIOC基于注解配置

一、Spring基于注解配置

1.1、组件注册注解

(1)、@Configuration

用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

注意:@Configuration注解的配置类有如下要求:

  • @Configuration不可以是final类型;

  • @Configuration不可以是匿名类;

  • 嵌套的configuration必须是静态类。

@Configuration
public class AppConfig {
}

(2)、@ComponentScan

用于指定 spring 在初始化容器时要扫描的包。 作用和在 spring 的 xml 配置文件中的:<context:component-scan base-package="org.example"/>

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    // ...
}
/*
basePackages与value:  用于指定包的路径,进行扫描

basePackageClasses: 用于指定某个类的包的路径进行扫描

nameGenerator: bean的名称的生成器

useDefaultFilters: 是否开启对@Component,@Repository,@Service,@Controller的类进行检测

includeFilters: 包含的过滤条件

            FilterType.ANNOTATION:按照注解过滤

            FilterType.ASSIGNABLE_TYPE:按照给定的类型

            FilterType.ASPECTJ:使用ASPECTJ表达式

            FilterType.REGEX:正则

            FilterType.CUSTOM:自定义规则

excludeFilters: 排除的过滤条件,用法和includeFilters一样
*/

(3)、@Bean

该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。

@Configuration
public class AppConfig {
    @Bean
    public TransferServiceImpl transferService() {
        return new TransferServiceImpl();
    }
}

(4)、@Scope

指定对象的作用范围:

  • singleton :默认值,单例的.
  • prototype :多例的.
  • request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
  • session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
  • global session:WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session.
@Configuration
public class FactoryMethodComponent {
    @Bean @Scope("prototype")
    public TestBean prototypeInstance(InjectionPoint injectionPoint) {
        return new TestBean("prototypeInstance for " + injectionPoint.getMember());
    }
}

(5)、@Lazy

是否延迟加载

(6)、@Conditional

按照一定的条件进行判断,满足条件给容器注册bean。

//此注解可以标注在类和方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) 
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

从代码中可以看到,需要传入一个Class数组,并且需要继承Condition接口,实现matches方法,返回true则注入bean,false则不注入。:

public interface Condition {
    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

(7)、@Import

用于导入其他配置类((4.2 版本之前只可以导入配置类,4.2版本之后 也可以导入普通类)),在引入其他配置类时,可以不用再写@Configuration 注解。功能就是和Spring XML 里面 的 一样

@Configuration
public class ConfigA {
    @Bean
    public A a() {
        return new A();
    }
}

@Configuration
@Import(ConfigA.class)
public class ConfigB {
    @Bean
    public B b() {
        return new B();
    }
}

三种用法:

  • 直接填class数组方式
    • @Import({ 类名.class , 类名.class... })
      public class TestDemo {}
      
  • ImportSelector方式【重点】
    • public class Myclass implements ImportSelector {
          /*
          String[]: 就是我们实际上要导入到容器中的组件全类名【重点 】
      	AnnotationMetadata:表示当前被@Import注解给标注的所有注解信息【不是重点】
          */
          @Override
          public String[] selectImports(AnnotationMetadata annotationMetadata) {
              return new String[]{"com.yc.Test.TestDemo3"};
          }
      }
      @Import({ 类名.class , Myclass.class... })
      public class TestDemo {}
      
  • ImportBeanDefinitionRegistrar方式
    • public class Myclass2 implements ImportBeanDefinitionRegistrar {
          /*
          AnnotationMetadata: 表示当前被@Import注解给标注的所有注解信息
      	BeanDefinitionRegistry:表示用于注册定义一个bean
          */
          @Override
          public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
              //指定bean定义信息(包括bean的类型、作用域...)
              RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo4.class);
              //注册一个bean指定bean名字(id)
              beanDefinitionRegistry.registerBeanDefinition("TestDemo4444",rootBeanDefinition);
          }
      }
      
      @Import({ 类名.class , Myclass2.class... })
      public class TestDemo {}
      

(8)、Factorybean

public interface FactoryBean<T> {

    //返回的对象实例
    T getObject() throws Exception;
    //Bean的类型
    Class<?> getObjectType();
    //true是单例,false是非单例  在Spring5.0中此方法利用了JDK1.8的新特性变成了default方法,返回true
    boolean isSingleton();
}

@Component
public class FactoryBeanLearn implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        //这个Bean是我们自己new的,这里我们就可以控制Bean的创建过程了
        return new FactoryBeanServiceImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return FactoryBeanService.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

1.2、生命周期注解

(1)、@Bean指定初始化和销毁方法

public class Car {
  	public Car() {
        System.out.println("无参构造初始化");
    }
    public void init() {
        System.out.println("CarBean---init");
    } 
    public void destory() {
        System.out.println("CarBean---destory");
    }
}

@Configuration
public class BeanLife {
    @Bean(initMethod="init", destroyMethod="destory") 
    public Car car() {
        return new Car();    
    }
}

(2)、InitializingBean和DisposableBean接口

@Component
public class Cat implements InitializingBean, DisposableBean{
    public Cat() {
        System.out.println("cat 构造函数...");
    }
    //初始化方法
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat afterPropertiesSet"); 
    }
    //销毁方法
    public void destroy() throws Exception {
        System.out.println("cat destory");  
    }
}

(3)、@PostConstruct和@Predestory

public Class XXX {
    public XXX() {}

    @PostConstruct
    private void init() {
        System.out.println("@PostConstruct将在依赖注入完成后被自动调用" );
    }
  
   @Predestory
   private void preDestory() {
       System.out.println("XXX 正在被容器删除");
   }
}

(4)、BeanPostProcessor接口

1.3、自动装配注解

(1)、@Autowired

​ 自动按照类型注入。当使用注解注入属性时,set 方法可以省略。它只能注入其他 bean类型。当有多个类型匹配时,使用要注入的对象变量名称作为 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到就报错。

(2)、@Qualifier

​ 在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和@Autowire 一起使用;但是给方法参数注入时,可以独立使用。

(3)、@Primary

​ 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常

(4)、@Resource

​ 默认按名称装配,当找不到与名称匹配的bean才会按类型装配。

(5)、@Inject

​ 基于类型来查找bean注入的,如果需要指定名称beanName

(6)、Profile

1.4、属性赋值注解

(1)、@Value

​ 主要用于赋值,该值可以是取值配置文件中的,也可以直接赋值,也可以使用SpEl表达式进行计算的结果,抑或直接从环境变量中获取。 该注解不能处理日期类赋值。

  • 基本数值
  • 可以写SpEL; #{}
  • 可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值)

(2)、@PropertySource加载配置文件

​ 主要用于加载配置文件,value值为classpath等价于 <context:property-placeholder location="classpath:student.properties"/>

  • 若使用@Component方式注入对象,则@PropertySource放置在普通类Student或配置类中都可以

  • 若使用@Bean方式注入Student对象,则@PropertySource必须放在配置类上加载

方式一:

@PropertySource({"classpath:/student.properties"})//指定配置文件classPath
@Component 
public class Student {
    @Value("张三")//直接赋值
    private String name;
    
    @Value("${stu.name}")//从配置文件中取值
    private String alias;
    
    @Value("${os.name}")//从容器中读取环境变量
    private String system;
    
    @Value("#{33-12}")//使用SpEL 计算
    private Integer age;
    
//    @Value("${stu.birthDate}")//不能处理日期
    private Date birthDate;
    
    @Value("${stu.hasNickName}") //布尔值
    private Boolean hasNickName;
}

方式二:


public class Student {
    @Value("张三")//直接赋值
    private String name;
    
    @Value("${stu.name}")//从配置文件中取值
    private String alias;
    
    @Value("${os.name}")//从容器中读取环境变量
    private String system;
    
    @Value("#{33-12}")//使用SpEL 计算
    private Integer age;
    
//  @Value("${stu.birthDate}")//不能处理日期
    private Date birthDate;
    
    @Value("${stu.hasNickName}") //布尔值
    private Boolean hasNickName;
}

@Configuration
@PropertySource({"classpath:/student.properties"})
public class PropertyValueConfig {
     @Bean
    public Student student(){
        return new Student();
    }
}
posted @ 2020-05-17 22:08  ciyelc  阅读(83)  评论(0)    收藏  举报