Spring框架进阶常见组件

Posted 烟锁迷城

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架进阶常见组件相关的知识,希望对你有一定的参考价值。

目录

1、Spring基本编程思想

2、配置组件

2.1、@Configuration IOC容器

2.2、@ComponentScan 指定读取目录

 2.3、@Scope 作用域

2.4、@Lazy 懒加载

2.5、@Conditional 条件加载

2.6、@Import 外部引入

 2.7、生命周期控制

2.7.1、注解控制

2.7.2、接口实现

2.7.3、@Bean的参数实现

2.7.4、生命周期统一管理

2.8、Bean注册方式总结

3、自动装配组件

3.1、@Component 组件声明

3.2、@Value 普通数据赋值

3.3、@Autowired 类型装配

3.4、@PropertySource 配置文件赋值

3.5、@Qualifier 多实例指定

3.6、@Primary 首选者

3.7、@Resource 名称装配

4、织入组件

4.1、ApplicationContextAware

4.2、BeanDefinitionRegistryPostProcessor

5、切面组件

5.1、@EnableTransactionManagement

5.2、@Transactional


Spring是Java开发中最重要的开发框架,可以说现在所有的Java开发者都必须要了解和使用的一种框架。 

1、Spring基本编程思想

Spring的编程思想
Spring思想应用场景特点
OOP

Object Oriented Programming(面向对象编程)

用程序归纳总结一切事务

封装,继承,多态
BOP

Bean Oriented Programming(面向Bean编程)

面向Bea你(普通的Java类)设计程序,解放程序员

Bean是一切的开始
AOP

Aspect Oriented Programming(面向切面编程)

找出多个类中具有规律的代码,开发时拆开,运行时合并,面向切面编程,即面向规则编程

解耦
IOC

Inversion of Control(控制反转)

将new对象的动作交给Spring管理,并由Spring保存已创建的对象(IOC容器)

转交控制权给容器
DI/DL

Dependency Injection(依赖注入)或Dependency Lookup(依赖查找)

依赖注入,依赖查找,Spring不禁保存自己创建的对象,而且保存对象与对象之间的关系,注入即赋值,主要是三种方式:

1、构造方法

2、set注入

3、直接赋值

自动赋值

2、配置组件

2.1、@Configuration IOC容器

@Configuration注解起到的功能是将一个类作为IOC容器,在类的内部方法上,如果增加了@Bean注解,则将这个方法返回的类作为Bean装载到IOC中

具体使用方式如下:

@Configuration
public class config 
    
    @Bean
    public User user()
        return new User();
    

在程序启动之后,IOC就会加载一个User的Bean,可以通过类型或者名称两种方式进行获取。依照名称的方式进行获取的话,在@Bean没有指定名称时,按照规则:

  1. 创建的Bean名称默认为类名小写,即user
  2. 其次会将函数名称指定为Bean
  3. 如果指定@Bean("user"),则依照指定名称进行获取。
@Configuration
public class config 

    @Bean("user")
    public User user()
        return new User();
    

2.2、@ComponentScan 指定读取目录

在配置类上添加@ComponentScan注解,该注解默认会扫描该类所在的包下所有的配置类。

 具体使用方式如下:

@ComponentScan("com.spring.example.courseone.project")
public class Config 

 增加这个注解之后,将按照默认规则对包下的类进行加载。

默认规则为,只扫描带有@Controller,@Service,@Component,@Repository注解的类。

除了按照默认规则之外,还有其他的规则。

增加注解@Filter,这个注解属于@ComponentScan,可以根据FilterType的类型对规则进行定义。

FilterType是一个枚举类,其中包含几种可以使用的过滤方式,比如注解,类,切点,正则表达式,自定义规则。

public enum FilterType 
    ANNOTATION,
    ASSIGNABLE_TYPE,
    ASPECTJ,
    REGEX,
    CUSTOM;

    private FilterType() 
    

 使用注解过滤器,指定包下类所加载的注解类型,即可指定加载Bean

@Configuration
@ComponentScan(value = "com.spring.example.courseone.project",
        includeFilters = 
                @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class))
public class ComponentScanConfig 

 使用类过滤器,指定包下类,即可指定加载类进入IOC

@Configuration
@ComponentScan(value = "com.spring.example.courseone.project",
        includeFilters = 
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Person.class))
public class ComponentScanConfig 

 使用自定义过滤器,指定一个自定义的过滤器类,即可让将指定的类型装载。

@Configuration
@ComponentScan(value = "com.spring.example.courseone.project",
        includeFilters = 
                @ComponentScan.Filter(type = FilterType.CUSTOM, value = MyTypeFilter.class))
public class ComponentScanConfig 

 自定义过滤器,需要继承TypeFilter接口,实现match方法,完成自定义规则的构建。

match的两个参数,metadataReader具有正在操作的类的信息,metadataReaderFactory具有上下文中所有的信息,可以根据这些能获取到的数据,进行对应的过滤

public class MyTypeFilter implements TypeFilter 

    /**
     * 自定义过滤规则
     * 
     * @param metadataReader        当前正在操作的类的信息
     * @param metadataReaderFactory 上下文中所有的信息
     * @return 是否加载
     * @throws IOException IO错误
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException 
        //获取当前类的所有注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前类的所有信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类的所有资源信息
        Resource resource = metadataReader.getResource();

        String className = classMetadata.getClassName();
        if (className.contains("User")) 
            return true;
        
        return false;
    

 2.3、@Scope 作用域

用于指定类的作用域

 具体使用方式如下:

@Configuration
public class ScopeConfig 
    
    @Bean
    @Scope("prototype")
    public Person person() 
        return new Person();
    
  1.  prototype:原型,多实例
  2. singleton:单例
  3. request:web模块,同一次请求只创建一个对象
  4. session:web模块,同一个session只创建一个对象
  5. 默认:同singleton,单例

2.4、@Lazy 懒加载

表示延迟初始化

 具体使用方式如下:

@Configuration
public class LazyConfig 

    @Bean
    @Lazy
    public Person person() 
        System.out.println("创建person");
        return new Person();
    

在容器IOC初始化的时候,这个类不会被加载,只有在使用的时候才会被加载,但是要注意,只有单例Bean才可以使用这个注解

2.5、@Conditional 条件加载

Spring4开始提供,它的作用是按照条件判断Bean是否装载到IOC中

创建ConditionOne,实现Condition接口,完成matches类,这里可以用beanFactory实现对Bean的加载监控,确定条件

public class ConditionOne implements Condition 

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) 
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Environment environment = context.getEnvironment();
        if (beanFactory.containsBean("user")) 
            return true;
        
        return false;
    

创建ConditionTwo,实现Condition接口,完成matches类,这里可以用Environment 实现对环境的配置监控,确定条件

public class ConditionTwo implements Condition 

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) 
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if (property.contains("Window")) 
            return true;
        
        return false;
    

将条件放入@Conditional注解中,即可实现对应条件的加载

@Configuration
public class ConditionalConfig 

    @Bean
    public User user() 
        System.out.println("创建user");
        return new User();
    

    @Conditional(ConditionOne.class)
    @Bean
    public Person sam() 
        System.out.println("创建sam");
        return new Person();
    

    @Conditional(ConditionTwo.class)
    @Bean
    public Person lily() 
        System.out.println("创建lily");
        return new Person();
    

除了基础注解@Conditional,还有一些实现注解,同样常用,就不再一一列举

2.6、@Import 外部引入

导入外部资源

@Import注解使用起来非常简单,可以直接对外部类进行注入

@Configuration
@Import(User.class)
public class ImportsConfig 

除了直接使用,还可以一次加载多个,这就需要继承ImportSelector接口来实现

public class MyImportSelector implements ImportSelector 

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) 
        return new String[] 
                "com.spring.example.courseone.project.model.Cat","com.spring.example.courseone.project.model.Dog"
        ;
    

 在@Import注解里加上MyImportSelector类

@Configuration
@Import(User.class,MyImportSelector.class)
public class ImportsConfig 

可以发现,使用@Import注解加载的类都是全类名加载

 想要实现按照某些条件进行加载,用@Import同样可以达成,需要实现ImportBeanDefinitionRegistrar接口。

可以看到,需重写的方法带有参数BeanDefinitionRegistry ,它可以获取到当前IOC的Bean,也可以将Bean注册到IOC中。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar 

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) 
        boolean cat = registry.containsBeanDefinition("com.spring.example.courseone.project.model.Cat");
        boolean dog = registry.containsBeanDefinition("com.spring.example.courseone.project.model.Dog");
        if (cat && dog) 
            registry.registerBeanDefinition("user", new RootBeanDefinition(User.class));
        
    

在@Import注解中加入 MyImportBeanDefinitionRegistrar 类

@Configuration
@Import(User.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class)
public class ImportsConfig 

 2.7、生命周期控制

2.7.1、注解控制

类的生命周期可以使用注解进行控制

  1. @PostConstruct,指定初始化方法,作用域为方法
  2. @PreDestroy,指定销毁方法,作用域为方法
  3. @DependsOn,定义Bean初始化及销毁时的顺序
@Component
public class CourseA 

    public CourseA() 
        System.out.println("创建课程");
    

    @PreDestroy
    public void close() 
        System.out.println("销毁课程");
    

    @PostConstruct
    public void start() 
        System.out.println("初始化课程");
    

2.7.2、接口实现

除了使用注解,还可以实现 InitializingBean, DisposableBean接口

@Component
public class CourseB implements InitializingBean, DisposableBean 
    @Override
    public void destroy() throws Exception 
        System.out.println("销毁课程");
    

    @Override
    public void afterPropertiesSet() throws Exception 
        System.out.println("初始化课程");
    

2.7.3、@Bean的参数实现

还可以使用@Bean注解

public class CourseC 

    public CourseC() 
        System.out.println("Course构造");
    

    public void start() 
        System.out.println("开始上课");
    

    public void close() 
        System.out.println("停止上课");
    

@Configuration
@ComponentScan("com.spring.example.courseone.project.model")
public class LifeCycleConfig 

    @Bean(initMethod = "start", destroyMethod = "close")
    public CourseC Course() 
        return new CourseC();
    

2.7.4、生命周期统一管理

除了这些方式吗,还可以实现BeanPostProcessor接口

 实现BeanPostProcessor接口之后,可以统一管理所有Bean的创建和销毁过程,不需要再单独实现。

@Component
public class MyBeanPostProcessor implements BeanPostProcessor 

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException 
        System.out.println("创建之前 " + beanName);
        return bean;
    

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException 
        System.out.println("创建之后 " + beanName);
        return bean;
    

2.8、Bean注册方式总结

  1. @Bean直接导入单个类
  2. @ComponentScan扫描指定包下的类
  3. @Import直接注入
  4. 实现ImportSelector
  5. 实现ImportBeanDefinitionRegistrar
  6. FactoryBean负责注册Bean,BeanFactory负责从容器中获取Bean

3、自动装配组件

3.1、@Component 组件声明

@Component是声明组件的注解,@Controller,@Service,@Repository三个注解是子类,用于标记不用的业务层级,本身并无其他作用和意义

3.2、@Value 普通数据赋值

@Value注解需要在IOC托管的Bean中才能生效

  1. 可以对参数直接赋值
  2. 允许逻辑计算
  3. 读取配置文件的配置数值
public class Teacher 

    @Value("山姆")
    private String name;
    @Value("#20-2")
    private int age;
    @Value("$teacher.sex")
    private String sex;

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public int getAge() 
        return age;
    

    public void setAge(int age) 
        this.age = age;
    

    public String getSex() 
        return sex;
    

    public void setSex(String sex) 
        this.sex = sex;
    

3.3、@Autowired 类型装配

@Autowired注解的作用是按类型装配,无法按名称装配。如果想要用名称装配,需要配合@Qualifier注解使用。对于@Service等注解,加入容器的Bean的默认名称为类名首字母小写,这也就意味着,@Qualifier注解的优先级高于@Autowired

@Controller
public class MyController 
    
    @Autowired
    private MyService myService;
@Controller
public class MyController 

    @Qualifier("myService")
    @Autowired
    private MyService myService;

3.4、@PropertySource 配置文件赋值

@PropertySource读取指定配置文件的数值

@Configuration
@PropertySource("classpath:application.properties")
public class PropertySourceConfig 

    @Bean
    public Teacher teacher() 
        return new Teacher();
    

3.5、@Qualifier 多实例指定

在有多个同类的Bean的情况下,可以使用@Qualifier注解指定Bean的名字来确定最终使用哪一个Bean,可以和@Autowired注解配合使用。

@Controller
public class MyController 

    @Qualifier("service")
    @Autowired
    private MyService myService;

3.6、@Primary 首选者

在具有多个同类型,同名的Bean时,需要@Primary确定IOC最优先使用的Bean,避免程序运行出现问题

@Configuration
public class PrimaryConfig 

    @Primary
    @Bean("teacher")
    public Teacher teacherA() 
        return new Teacher();
    

    @Bean("teacher")
    public Teacher teacherB() 
        return new Teacher();
    

3.7、@Resource 名称装配

@Resource的作用与@Autowired相同,但是查找顺序不同,默认按名称装配,当找不到与名称匹配的Bean时才按照类型装配,如果指定名称,则只按照名称寻找。

@Controller
public class MyController 

    @Resource(name = "myService")
    private MyService myService;

4、织入组件

4.1、ApplicationContextAware

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

4.2、BeanDefinitionRegistryPostProcessor

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

5、切面组件

5.1、@EnableTransactionManagement

添加对事物的管理

@SpringBootApplication
@EnableTransactionManagement
public class CourseOneApplication 

    public static void main(String[] args) 
        ApplicationContext applicationContext = SpringApplication.run(CourseOneApplication.class, args);
        for (String className : applicationContext.getBeanDefinitionNames()) 
            System.out.println(className);
        
    

5.2、@Transactional

配置声明式事物信息,只需要在方法上添加此注解即可开启事务

以上是关于Spring框架进阶常见组件的主要内容,如果未能解决你的问题,请参考以下文章

SSH进阶之路一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架

Web应用的组件化进阶篇

Spring框架进阶Spring V2.0 AOP

从 0 开始手写一个 Spring MVC 框架,向高手进阶!

福利大放送!美团推出Spring源码进阶宝典:脑图+视频+文档

Spring框架进阶Spring V3.0 AOP源码分析流程