Spring框架进阶常见组件
Posted 烟锁迷城
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架进阶常见组件相关的知识,希望对你有一定的参考价值。
目录
4.2、BeanDefinitionRegistryPostProcessor
5.1、@EnableTransactionManagement
Spring是Java开发中最重要的开发框架,可以说现在所有的Java开发者都必须要了解和使用的一种框架。
1、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没有指定名称时,按照规则:
- 创建的Bean名称默认为类名小写,即user
- 其次会将函数名称指定为Bean
- 如果指定@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();
- prototype:原型,多实例
- singleton:单例
- request:web模块,同一次请求只创建一个对象
- session:web模块,同一个session只创建一个对象
- 默认:同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、注解控制
类的生命周期可以使用注解进行控制
- @PostConstruct,指定初始化方法,作用域为方法
- @PreDestroy,指定销毁方法,作用域为方法
- @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注册方式总结
- @Bean直接导入单个类
- @ComponentScan扫描指定包下的类
- @Import直接注入
- 实现ImportSelector
- 实现ImportBeanDefinitionRegistrar
- FactoryBean负责注册Bean,BeanFactory负责从容器中获取Bean
3、自动装配组件
3.1、@Component 组件声明
@Component是声明组件的注解,@Controller,@Service,@Repository三个注解是子类,用于标记不用的业务层级,本身并无其他作用和意义
3.2、@Value 普通数据赋值
@Value注解需要在IOC托管的Bean中才能生效
- 可以对参数直接赋值
- 允许逻辑计算
- 读取配置文件的配置数值
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框架
从 0 开始手写一个 Spring MVC 框架,向高手进阶!