Spring五、注解编程基础组件


  Spring5开启了零配置编程时代,脱离xml完全使用注解编程,为Spring Boot奠定了开发基础。
  案例demo地址

一、配置组件

1. @Configuration

  声明一个类为Spring IOC容器,如果这个类方法头上注册了@Bean,就会作为Spring容器中的Bean。等价于xml配置文件。

@Configuration
public class MyConfig {

    /**
     * 1. 默认类名首字母小写
     * 2. 其次就是取方法名
     * 3. 最后优先取Bean的value
     * @return
     */
    @Bean(value = "myPerson")
    public Person getPerson() {
        System.out.println("create person by myself");
        return new Person("shen", "18");
    }

}
  普通xml方式配置的IOC容器获取方法:
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
    Person person = (Person) applicationContext.getBean("myPerson");
  注解@Configuration方式配置的IOC容器获取方法:
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
    Person person = (Person) applicationContext.getBean("person");

2. @ComponentScan、@ComponentScans

  在配置类上添加@ComponentScan注解,相当于之前的context:component-scan

@Configuration
//1. 简单使用ComponentScan注解扫描,扫描包下的bean使用@Service、@Controller、@Component等注解配合,可以扫描到
//@ComponentScan(value = "com.bigshen.demo.project")
//2. useDefaultFilters = false, 不使用Spring默认的扫描filter,
//  自己指定扫描规则
@ComponentScan(
        value = "com.bigshen.demo.project",
        useDefaultFilters = false,       // 使用自定义的扫描过滤规则
        includeFilters = {
//                @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),  // 使用注解扫描
//                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyDao.class),     // 直接指定类型扫描
                @ComponentScan.Filter(type = FilterType.CUSTOM, value = MatchedFilter .class)},     // 直接自定义类型扫描
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.CUSTOM, value = UnMatchedFilter.class)   // 直接自定义类型排除
        }
        )
public class MyConfig {


}



public class MatchedFilter implements TypeFilter {

    /**
     *
     * @param metadataReader  类的信息
     * @param metadataReaderFactory  spring上下文
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {

        // 当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        // 当前类的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        // 当前资源信息
        Resource resource = metadataReader.getResource();

        String clazzName = classMetadata.getClassName();
        System.out.println("--------- " + clazzName);

        if (clazzName.contains("er")){
            return true;
        }
        return false;
    }

}


public class UnMatchedFilter implements TypeFilter {

    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {

        ClassMetadata classMetadata = metadataReader.getClassMetadata();

        String className = classMetadata.getClassName();
        if (className.contains("Controller")) {
            // 不匹配
            return true;
        }
        return false;
    }

}

3. @Scope

  指定类的作用域,singleton、prototype、request、session

4. @Lazy

  Spring中Bean默认是非懒加载的,即在容器初始化时就将实例初始化,使用@Lazy注解指定该Bean为懒加载。

5. @Conditional

  Spring4开始提供,按照一定的条件进行判断,满足条件给容器注册Bean。 自定义的条件实现'org.springframework.context.annotation.Condition'

  public class WindowCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Environment environment = context.getEnvironment();
        String system = environment.getProperty("os.name");
        System.out.println("System --  " + system);
        if (system.contains("Window")) {
            return true;
        }
        return false;
    }

}

@Configuration
public class MyConfig {

    @Conditional(WindowCondition.class)
    @Bean
    public Person shen() {
        System.out.println("将shen添加到ioc容器中");
        return new Person("Shen", "18");
    }

    @Bean
    @Conditional(LinuxCondition.class)
    public Person liu() {
        System.out.println("将liu添加到ioc容器中");
        return new Person("liu", "18");
    }

    @Bean
    @Conditional(WindowCondition.class)
    public Person wang() {
        System.out.println("将wang添加到ioc容器中");
        return new Person("wang", "18");
    }

}

6. @Import

  导入外部资源
  @Import源码,可以指定 org.springframework.context.annotation.ImportSelector 或者 org.springframework.context.annotation.ImportBeanDefinitionRegistrar 的实现类来作为导入规则,也可以是普通的类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
	 * or regular component classes to import.
	 */
	Class<?>[] value();

}

  
@Configuration
@Import(value = {Cat.class, MyImport.class, MyRegistry.class})
public class MyConfig {

    /**
     *
     * 注册Bean的几种方式
     * 1. @Bean 导入单个Bean
     * 2. @ComponentScan (默认扫描 @Controller、@Service、@Repository、@Component)
     * 3. @Import 快速导入Bean
     *      a. @Import 直接参数导入
     *      b. 实现 ImportSelector 自定义规则实现
     *      c. 实现 ImportBeanDefinitionRegistrar 直接往IOC容器中注册
     * 4. FactoryBean , 把需要注册的对象封装为FactoryBean
     *      a. FactoryBean 负责将Bean注册到Ioc的Bean
     *      b. BeanFactory Ioc容器,从中获得Bean对象
     * @return
     */
    @Bean
    public Person person() {
        return new Person("shen", "19");
    }

    @Bean
    public FactoryBean world() {
        return new MyFactoryBean();
    }

}


public class MyImport implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 直接返回 class集合,放入IOC容器
        return new String[]{"com.bigshen.demo.project.entity.Apple", "com.bigshen.demo.project.entity.Orange"};
    }

}

public class MyRegistry implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 包里同时声明了Apple 和 Orange ,才把Fruit放入IOC容器

        Boolean containsApple = registry.containsBeanDefinition("com.bigshen.demo.project.entity.Apple");
        Boolean containsOrange = registry.containsBeanDefinition("com.bigshen.demo.project.entity.Orange");

        if (containsApple && containsOrange) {
            BeanDefinition beanDefinition = new RootBeanDefinition(Apple.class);
            registry.registerBeanDefinition("apple", beanDefinition);
        }

    }

}

public class MyFactoryBean implements FactoryBean<World> {

    @Override
    public World getObject() throws Exception {
        return new World();
    }

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

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

7.生命周期控制 @PostConstruct、@PreDestroy、@DependsOn

  @PostConstruct 用在方法上,用于指定Bean的初始化方法
  @PreDestroy 用在方法上,用于指定销毁方法
  @DependsOn 定义Bean初始化及销毁时的顺序

  /**
     *  bean的生命周期 : 创建(实例化-初始化)、使用、销毁
     * 3中方式都可实现 对生命周期进行控制:
     * a、@PostConstruct、@PreDestroy
     * b、@Bean本身的 initMethod()、destroyMethod()
     * c、接口 InitializingBean#afterPropertiesSet()、DisposableBean#destroy()
     * @return
     */

Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

1、Bean自身的方法  :  这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法

2、Bean级生命周期接口方法  :  这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法

3、容器级生命周期接口方法  :  这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。

4、工厂后处理器接口方法  :  这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器  接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

二、赋值组件、自动装配

1. @Componment

  泛指组件,当组件不好归类时使用

2. @Service、@Controller、@Repository

  @Service 用于标注业务层组件
  @Controller 用于标注控制层组件
  @Repository 用于标注数据访问层、即Dao层组件

3. @Value

  普通数据类型赋值 可结合Spring EL表达式从配置文件取值

    @Value("${child.family}")
    private String family;

4. @Autowired

  默认按照类型装配,如果想按名称进行装配,可配合@Qualifier使用

5. @Resource

  按照名称装配,如果找不到名称匹配的Bean则会按照类型装配

6 @PropertySource

  读取配置文件

@Configuration
@PropertySource("classpath:values.properties")
public class MyConfig {

    @Bean
    public Child child() {
        return new Child();
    }

}

7. @Qualifier

  如存在多个实例,配合@Autowired使用,指定根据名称装配

    @Autowired
    @Qualifier("childService")
    public HumanService humanService;

8. @Primary

  自动装配时如果匹配到多个Bean,使用@Primary作为首选者,否则抛出异常
  如一个接口有多个实现类,这些实现类中有一个使用了@Primary注解,则在@Autowired注入时会优先使用这个实现类

三、织入组件

1. ApplicationContextAware

  可以通过这个上下文环境对象得到Spring容器中的Bean

2. BeanDefinitionRegistryPostProcessor

  BeanDefinitionRegistryPostProcessor实现了BeanFactoryPostProcessor接口,是Spring框架的BeanDefinitionRegistry的后处理器,用来注册额外的BeanDefinition

四、切面组件

1. @EnableTransactionManagement

 启用对事物管理的支持

2. @Transactional

 配置声明式事物信息

posted @ 2020-03-01 16:53  BigShen  阅读(525)  评论(0编辑  收藏  举报