配置类组件
@Configuration(把一个类作为IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean)
以前我们是用xml的配置文件作为IoC容器的启动入口
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.example.entity.Person">
<property name="name" value="Tom"></property>
<property name="age" value="18"></property>
</bean>
</beans>
写一个测试类:
ApplicationContext appcontext = new ClassPathXmlApplicationContext("application.xml");
Person person = (Person) appcontext.getBean("person");
System.out.println(person);
我们便可以通过这样的方式来取到Bean。
现在有了@Configuration注解我们便可以不用再写xml:
@Configuration
public class MyConfiguration {
//默认是类名首字母小写
//取方法名
//优先取@Bean注解的value
@Bean("person2")
public Person person(){
return new Person("mic",18);
}
}
ApplicationContext appcontext = new AnnotationConfigApplicationContext(MyConfiguration.class);
Person person = (Person) appcontext.getBean("person");
System.out.println(person);
@ComponentScan(在配置类上添加@ComponentScan注解。该注解默认会扫描该类所在的包下所有的配置类,相当于xml中的<context:component-scan>)
包扫描会扫描只要标注了@Controller,@Service,@Repository,@Component这四个注解都会被扫描到容器中。
也可以自定义扫描规则
@Configuration
@ComponentScan(value = "com.example",
//指定扫描的注解 includeFilters = {@Filter(type= FilterType.ANNOTATION,value = {Controller.class})}
//指定扫描的类 includeFilters = {@Filter(type = FilterType.ASSIGNABLE_TYPE,value = {MyContorller.class})}
//自定义一个扫描规则 includeFilters = {@Filter(type = FilterType.CUSTOM,value = {MyTypeFilter.class})},
useDefaultFilters = false
)
public class MyConfiguration {
}
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader 获取当前正在操作的信息
* @param metadataReaderFactory 获取上下文中所有的信息
* @return
* @throws IOException
*/
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();
System.out.println("------" + className + "------");
if(className.contains("er")){
//类名包含‘er’的
return true;
}
return false;
}
}
@Scope(用户指定scope作用域)
//prototype 原型,多例
//singleton 单例 默认
//request 主要应用于web模块,同一次请求只创建一个实例
//session 主要应用于web模块,同一个session只创建一个实例
@Scope("prototype")
@Bean
public Person person(){
//IoC实例化对象的时候,并不是简单地调用我们定义的方法
return new Person("Tom",18);
}
@Lazy(延迟初始化)
未加@Lazy注解:
@Configuration
public class MyConfiguration {
@Bean("person2")
public Person person(){
System.out.println("将对象添加到IoC容器");
return new Person("mic",18);
}
}
@Test
public void test(){
ApplicationContext appcontext = new AnnotationConfigApplicationContext(MyConfiguration.class);
System.out.println("IoC容器初始化完成");
appcontext.getBean("person2");
}
运行结果:
加上@Lazy注解运行结果:
默认非延迟加载
懒加载只针对单例Bean起作用
默认容器启动时不创建对象,调用对象的功能时才创建
@Conditional(Spring 4开始提供,按照一定条件进行判断,满足条件给容器注册Bean)
假设:
如果操作系统是Windows,那么就将James实例化到容器中
如果操作系统是Linux,那么就将Tom实例化到容器中
@Configuration
public class MyConfig {
@Conditional(WinCondition.class)
@Bean
public Person mic(){
System.out.println("将对象Mic添加到IoC容器中");
return new Person("Mic",16);
}
@Conditional(WinCondition.class)
@Bean
public Person tom(){
System.out.println("将对象Tom添加到IoC容器中");
return new Person("Tom",18);
}
@Conditional(LinuxCondition.class)
@Bean
public Person james(){
System.out.println("将对象James添加到IoC容器中");
return new Person("James",17);
}
}
public class WinCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//从IoC容器中拿到已经实例化的对象
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
if(osName.contains("Windows")){
return true;
}
return false;
}
}
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println("IoC容器创建完成");
}
@Import(导入外部资源)
@Import 直接传参导入
@Import(Person.class)
ImportSelector 自定义导入规则
@Import(MyImportSelector.class)
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.gupaoedu.project.entity.Company",
"com.gupaoedu.project.entity.Member"};
}
}
ImportBeanDefinitionRegistrar ,使用BeanDefinitionRegistry可以手动注入到IoC容器中
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata 当前类的注解信息
* @param registry 完成BeanDefinition的注册
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean company = registry.containsBeanDefinition("com.gupaoedu.project.entity.Company");
boolean member = registry.containsBeanDefinition("com.gupaoedu.project.entity.Member");
if(company && member){
BeanDefinition beanDefinition = new RootBeanDefinition(User.class);
registry.registerBeanDefinition("user",beanDefinition);
}
}
}
给IoC中注册Bean的方式
1、@Bean 直接导入单个类
2、@ComponentScan 包扫描默认是扫描(@Controller、@Service、@Repository、@Component)
3、@Import 快速给容器导入组件Bean
a. @Import 直接传参导入
b. ImportSelector 自定义导入规则
c.ImportBeanDefinitionRegistrar ,使用BeanDefinitionRegistry可以手动注入到IoC容器中
4、FactoryBean 把需要注入的对象封装为FactoryBean
a、FactoryBean 负责将Bean注入到容器的Bean
b、BeanFactory 从IoC中获得Bean对象
FactoryBean注入方式
public class MyFactoryBean implements FactoryBean<Monkey> {
@Nullable
@Override
public Monkey getObject() throws Exception {
return new Monkey();
}
@Nullable
@Override
public Class<?> getObjectType() {
return Monkey.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Configuration
public class MyConfig {
@Bean
public MyFactoryBean monkey(){
return new MyFactoryBean();
}
}
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);
//通过FactoryBean注入的值
System.out.println("============" + app.getBean("monkey").getClass());
Object monkey1 = app.getBean("monkey");
Object monkey2 = app.getBean("monkey");
System.out.println("是否单例:" + monkey1 == monkey2);
//拿到构建monkey的FactoryBean
Object monkeyFactoryBean = app.getBean("&monkey");
System.out.println(monkeyFactoryBean);
}
}
Bean生命周期监控
1.添加initMethod 和 destroyMethod
@Bean(initMethod = "addOil",destroyMethod = "close")
2.实现InitializingBean和DisposableBean接口
@Component
public class Train implements InitializingBean,DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("火车对象销毁");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("火车对象初始化");
}
}
3.使用@PostConstruct和@PreDestroy注解
@Component
public class AirPlane {
public AirPlane() {
System.out.println("调用AirPlane的构造方法");
}
@PostConstruct
public void addOil(){
System.out.println("飞机飞行前加油");
}
public void run(){
System.out.println("正在空中巡航");
}
@PreDestroy
public void close(){
System.out.println("飞机落地熄火");
}
}
4、自己写一个类,实现BeanPostProcessor接口
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization" + beanName + "," + bean);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization" + beanName + "," + bean);
return bean;
}
}
可以针对于所有的类
赋值组件
@Component(泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注)
@Service(用于标注业务层组件)
@Controller(用于标注业务层组件)
@Repository(用于标注数据访问组件,即DAO组件)
@Value(普通数据类型赋值) @PropertySource(读取配置文件赋值)
@Configuration
@PropertySource("classpath:values.properties")
public class MyConfig {
@Bean
public Bird bird(){
return new Bird();
}
}
public class Bird {
//支持的类型
//1、基本数据类型
//3、Spring EL表达式
//4、通过配置文件赋值
@Value("鹦鹉")
private String name;
@Value("#{8-5}")
private int age;
@Value("${bird.color}")
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Bird() {
}
public Bird(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Bird{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}
@Autowired(默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用)
@Qualifier(如存在多个实例配合使用)
@Configuration
@ComponentScan({
"com.gupaoedu.project.controller",
"com.gupaoedu.project.service",
"com.gupaoedu.project.dao"
})
public class MyConfig {
@Bean("dao")
public MyDao dao(){
MyDao dao = new MyDao();
dao.setFlag("2");
return dao;
}
}
@Repository
public class MyDao {
private String flag = "1";
public void setFlag(String flag) {
this.flag = flag;
}
@Override
public String toString() {
return "MyDao{" +
"flag='" + flag + '\'' +
'}';
}
}
@Service
public class MyService {
@Qualifier("dao")
@Autowired
private MyDao myDao;
public void print(){
System.out.println(myDao);
}
}
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);
MyService service = app.getBean(MyService.class);
service.print();
}
}
运行结果flag = 2;
@Primary(自动装配时当出现多个Bean候选者时,被注释为@Primary的Bean将作为首选者,否则抛出异常)
@Configuration
@ComponentScan({
"com.gupaoedu.project.controller",
"com.gupaoedu.project.service",
"com.gupaoedu.project.dao"
})
public class MyConfig {
@Primary
@Bean("myDao")
public MyDao dao(){
MyDao dao = new MyDao();
dao.setFlag("9");
return dao;
}
@Bean("myDao")
public MyDao myDao(){
MyDao dao = new MyDao();
dao.setFlag("3");
return dao;
}
}
@Resource(默认按照名称装配,当找不到与名称匹配的bean才会按类型装配)
package com.gupaoedu.project.service;
import com.gupaoedu.project.dao.MyDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* Created by Tom.
*/
@Service
public class MyService {
@Resource(name="dao")
private MyDao myDao;
public void print(){
System.out.println(myDao);
}
}
织入组件
ApplicationContextAware(可以通过这个上下文环境对象得到Spring容器中的Bean)
参考:https://blog.csdn.net/qq_40718168/article/details/84062429
BeandefinitionRegistryPostProcessor
参考:https://blog.csdn.net/ztchun/article/details/90814135
切面组件
@EnableTransactionManagement(添加对事务管理的支持)
@Transactional(配置声明式事务信息)