本文共 23097 字,大约阅读时间需要 76 分钟。
作用:表明该类是一个配置类,内部其实是一个@Component
作用:向IOC容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id。
基本使用:
@Configurationpublic class TestConfig { @Bean public Person person() { return new Person("11", "张三"); }}
也可以指定bean的id:
@Bean("person")public Person person() { return new Person("11", "张三");}
作用:为容器中注册Bean
基本使用:
定义FactoryBean的实现类
// 泛型指定为要注册Bean的类型public class ColorFactoryBean implements FactoryBean{ // 返回要注册的Bean @Override public Color getObject() throws Exception { return new Color(); } // 返回Bean类型 @Override public Class getObjectType() { return Color.class; } // 指定是否单例 @Override public boolean isSingleton() { return true; }}
在配置类中注册FactoryBean
@Configurationpublic class TestConfig04 { // 注册FactoryBean @Bean public ColorFactoryBean colorFactoryBean() { return new ColorFactoryBean(); }}
注:
作用:扫描指定目录下的组件,若不指定目录,则扫描当前路径下的组件。
基本使用:
@Configuration@ComponentScanpublic class TestConfig { @Bean public Person person() { return new Person("11", "张三"); }}
还可以通过value或basePackages属性指定要扫描的包、includeFilters或excludeFilters指定要扫描或者要排除的类型,示例如下:
@Configuration@ComponentScan(basePackages = "com.zsp", includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})public class TestConfig { @Bean public Person person() { return new Person("11", "张三"); }}
@ComponentScan内部的一个注解,用来定义过滤规则,如按照注解过滤(如上例),按照类型过滤等。
作用:内部指定多个@Componentscan
基本使用:
@Configuration@ComponentScans(value = { @ComponentScan(basePackages = "com.zsp", includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class) })})public class TestConfig { ...}
作用:指定Bean的Scope(作用域)
注:Bean的四种作用域:Singleton、Prototype、Request、Session
基本使用:
指定Bean为单例
@Scope("singleton")// 单例@Beanpublic Person person() { return new Person("11", "张三");}
指定Bean为多例
@Scope("prototype")// 多实例@Beanpublic Person person() { return new Person("11", "张三");}
注:单例情况下,容器启动时就会调用方法创建对象到IOC容器中,以后每次获取就是直接从容器中(一级缓存)中拿;多实例状态下,IOC容器启动不会调用方法创建对象,而是获取时才调用。
作用:将Bean设置为懒加载(获取时才创建对象)
基本使用:
@Lazy // 懒加载@Beanpublic Person person() { return new Person("11", "张三");}
作用:按照一定条件判断,满足条件给容器中注册bean,一起看一下这个注解:
public @interface Conditional { Class [] value();}
@Conditional内部包含一个Condition数组,Condition是一个接口,我们可以通过写这个接口的实现类来实现对这个注解的配置。
如:
@Conditional(value = { UserCondition.class})@Bean("zhangsan")public User zhangsan() { return new User(15, "张三");}public class UserCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 1,获取Bean工厂 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 2,获取类加载器 ClassLoader classLoader = context.getClassLoader(); // 3,获取当前环境信息 Environment environment = context.getEnvironment(); // 4,获取Bean定义信息 BeanDefinitionRegistry registry = context.getRegistry(); return false; }}
Condition给我们提供的方法参数可以用来获取BeanFactory,环境等信息。
示例:若系统是Windows则注册bill组件,如系统是linux则注册linus组件:
首先实现Condition接口
// 实现Condition接口public class LinusCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name");//获取系统名称 if (property != null && property.contains("linux")) { return true; } return false; }}
接着环境变量和配置注解:
环境变量:-Dos.name=linux
注解配置:
@Conditional(value = { BillCondition.class})@Bean("bill")public User bill() { return new User(88, "Bill Gates");}@Conditional(value = { LinusCondition.class})@Bean("linus")public User linus() { return new User(88, "linus");}
标注在类上:满足当前条件,这个类中配置的所有的bean才能生效(统一设置)。
作用:快速给容器中导入一个组件(id默认是组件的全类名)
补充:
基本使用:
// 定义一个Colorpublic class Color { ...}@Configuration@Import(value = { Color.class}) // 导入Color组件,id默认全类名,可以传入数组public class TestConfig03 { ...}
作用:返回需要导入的组件的全类名数组
使用步骤:
自定义类实现ImportSeletor接口,并重写selectImports()方法
public class TestImportSeletor implements ImportSelector { /** * * @param importingClassMetadata 获取被@Import标注的类的信息 * @return 返回要注入组件的全类名数组 */ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{ "com.zsp.domain.Color"}; }}
配置类加上该注解
@Configuration@Import(value = { TestImportSeletor.class})public class TestConfig03 { ... }
注意:该方法导入的bean id也是bean的全类名。
作用:给容器中注册组件
基本使用:
定义类实现 ImportBeanDefinitionRegistrar 接口并重写 registerBeanDefinitions() 方法
public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean containsColor = registry.containsBeanDefinition("com.zsp.domain.Color"); if (containsColor) { // 指定Bean定义信息 注意这里需要传入类型 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Green.class); registry.registerBeanDefinition("green", rootBeanDefinition); } }}
2,注解配置该实现类
@Configuration@Import(value = { Color.class, TestImportBeanDefinitionRegistrar.class})public class TestConfig03 { ... }
基本使用:
Bean中书写初始化和销毁方法
public class Car { public Car() { System.out.println("创建..."); } // 初始化方法 public void init() { System.out.println("init..."); } // 销毁方法 public void destroy() { System.out.println("destroy..."); }}
@Bean注解配置初始化和销毁方法
@Configurationpublic class TestConfig05 { // 配置初始化和销毁方法 @Bean(name = "car", initMethod = "init", destroyMethod = "destroy") public Car car() { return new Car(); }}
备注:
基本使用:
分别实现两接口的 afterPropertiesSet() 和 destroy() 方法
// 实现两接口并实现初始化和销毁方法public class Cat implements InitializingBean, DisposableBean { public Cat() { System.out.println("Cat创建..."); } @Override public void destroy() throws Exception { System.out.println("销毁..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("初始化..."); }}
使用@Bean注入该组件
@Configurationpublic class TestConfig06 { @Bean(name = "cat") // 注册 public Cat cat() { return new Cat(); }}
基本使用:
组件类定义初始化和销毁方法并加上两注解
public class Dog { public Dog() { System.out.println("创建..."); } // 实例化之后调用 @PostConstruct public void init() { System.out.println("init..."); } // 销毁之前调用 @PreDestroy public void destroy() { System.out.println("destroy..."); }}
向容器中注册该组件
@Configurationpublic class TestConfig07 { @Bean(name = "dog") // 注册 public Dog dog() { return new Dog(); }}
作用:在bean初始化前后进行一些处理工作
BeanPostProcessor 接口内部提供两个方法:
postProcessBeforeInitialization:根据Spring官方的介绍,该方法将会在我们实现 InitializingBean 的初始化方法 和 @Bean中指定的 init-method 方法调用之前调用:
/** * Apply this {@code BeanPostProcessor} to the given new bean instance before any bean * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} * or a custom init-method). */@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean;}
postProcessAfterInitialization:类似的,该方法会在我们实现 InitializingBean 的初始化方法 和 @Bean中指定的 init-method 方法调用之后调用:
@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean;}
基本使用:
定义自定义后置处理器(实现 BeanPostProcessor)并将其注册到容器中,之后重写before和after两个方法:
@Component// 注册public class AnimalBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization: " + beanName + "...."); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization: " + beanName + "...."); return bean; }}
定义Animal类用来测试
public class Animal implements InitializingBean, DisposableBean { public Animal() { System.out.println("Animal construct ..."); } @Override public void destroy() throws Exception { System.out.println("DisposableBean destroy ..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("InitializingBean init ..."); } public void initMethod() { System.out.println("init-method ..."); } public void destroyMethod() { System.out.println("destroy-method ..."); }}
向容器中注册Animal,并定义初始化方法
@Configuration@ComponentScan(basePackages = "com.zsp")public class TestConfig08 { @Bean(name = "animal", initMethod = "initMethod", destroyMethod = "destroyMethod") public Animal animal() { return new Animal(); }}
测试结果
Animal construct ... // 构造方法postProcessBeforeInitialization: animal.... // before处理InitializingBean init ... // InitializingBean的afterPropertiesSet方法init-method ... // @Bean中配置的初始化方法init()postProcessAfterInitialization: animal.... //after处理
在IOC的初始化过程中,由populateBean(beanName) 对Bean进行属性赋值后,initializeBean()方法进行以下操作:
applyBeanPostProcessorsBeforeInitialiaztion(wrappedBean, beanName):首先由该方法获取所有的BeanPostProcessor,并挨个执行(遍历),一旦有一个返回null就会跳出循环,不会执行后续的processor brfore 方法:
@Overridepublic Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // getBeanPostProcessors() 获取所有的Bean processors // 遍历执行所有的processor for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; // 如果一个为null,则接下来的全部返回 } result = current; } return result;}
invokeInitMethods(beanName, wrappedBean, mbd):执行我们自定义的初始化方法(@Bean中定义的init-method和实现的afterPropertiesSet() 方法)
applyBeanPostProcessorsAfterInitialization(existingBean, beanName):同样的,在初始化方法执行完成之后执行,同样是获取所有的processor,遇null返回。
@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result;}
如 ApplicationContextAwareProcessor 就是用来处理 ApplicationContextAware 的初始化方法。例如,我们可以通过实现ApplicationContextAware来完成 ApplicationContextAwareProcessor 对 ApplicationContextAware的处理,并为我们在组件中实例化一个IOC容器:
@Componentpublic class Fish implements ApplicationContextAware { public ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}
又比如 AutowiredAnnotationBeanPostProcessor,帮助我们完成@Autowired标注属性的自动注入工作。
作用:属性赋值
用法:
写基本数值:
@Value("张三")private String name;
写SpEL表达式
@Value("#{1 + 1}")private Integer id;
${} 取出配置文件中的值:该方式在介绍下一个注解时介绍
备注:@Value同样可以用在方法参数上
作用:类似xml配置方式的< context:property-placeholder >标签,用来定义配置文件的位置并导入配置文件
用法:
定义配置文件 teacher.properties,内容如下:
teacher.name=张三teacher.id=1
在配置类中使用 @PropertySource 注入:
@Configuration@ComponentScan("com.zsp.domain")@PropertySource("classpath:teacher.properties")public class TestConfig09 { @Bean public Teacher teacher() { return new Teacher(); }}
实体类中:
public class Teacher { @Value("${teacher.id}") private Integer id; @Value("${teacher.name}") private String name; public Teacher() { }}
同样的,我们也可以通过环境变量来获取这些配置文件中的属性值:
@Testpublic void test2() { ApplicationContext ioc = new AnnotationConfigApplicationContext(TestConfig09.class); // 通过ioc容器获取环境变量 Environment environment = ioc.getEnvironment(); String property = environment.getProperty("teacher.name"); System.out.println(property);}
作用:自动注入(默认是优先按照类型去容器中找)
基本使用:
@Servicepublic class TestService { @Autowired private TestDao testDao; ...}
备注:@Autowired是有限按照类型去容器中找对应的组件,如果找到多个类型相同的组件,再将属性名称按照组件的id去容器中找
作用:指定要装配的组件id,和@Autowired配合使用
基本使用:
@Servicepublic class TestService { @Qualifier("testDao") // 指定组件id @Autowired private TestDao testDao; ...}
作用:让Spring进行自动装配时,默认使用首选(被该注解标注)的Bean。
作用:属性注入
基本使用:
@Resource(name = "testDao")private TestDao testDao;
和@Autowired的区别:
作用:属性注入
基本使用:
导包:
javax.inject javax.inject 1
使用:
@Injectprivate TestDao testDao;
和@Autowired的区别:
基本使用:
@Autowiredpublic void setTestDao(TestDao testDao) { this.testDao = testDao;}
备注:标注在方法上时,方法使用的参数将会从ioc容器中获取。
基本使用:
@Autowiredpublic TestService(TestDao testDao) { this.testDao = testDao;}
备注:标注在构造器上时,方法参数也是从容器中获取。如果组件只有一个有参构造器,那么有参构造器的@Autowired可以省略,参数位置的组件还是可以从容器中获取。
基本使用
public void setTestDao(@Autowired TestDao testDao) { this.testDao = testDao;}
即以下两种方式用不用@Autowired都一样,没有区别:
@Beanpublic Teacher teacher(@Autowired Classes classes) { return new Teacher(classes);}// 不加 @Autowired@Beanpublic Teacher teacher(Classes classes) { return new Teacher(classes);}
自定义组件中想要使用Spring容器中的一些组件,如:ApplicationContext、BeanFactory等,只需要自定义组件实现xxxAware,在创建对象时,会调用接口规定的方法注入相关组件。
使用实例:
@Componentpublic class Watch implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { // 获取Bean名称 @Override public void setBeanName(String name) { System.out.println("当前bean的name为:" + name); } // 获取ioc容器 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("当前ioc容器:" + applicationContext); } //获取String值解析器 @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String s = resolver.resolveStringValue("老师名字叫${teacher.name}, 今年#{15+20}岁"); System.out.println(s); }}
原理:
每一个xxxAware都有一个对应的xxxAwareProcessor用来处理,如ApplicationContextAware就有ApplicationContextAwareProcessor用来处理,前面对BeanPostProcessor的介绍我们知道:BeanPostProcessor的子类可以通过实现父类的postProcessBeforeInitialization()方法进行一些操作,这些AwareProcessor正是通过这个方法完成注入操作,下面是ApplicationContextAwareProcessor的源码:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware || bean instanceof ApplicationStartupAware)) { return bean; } AccessControlContext acc = null; if (System.getSecurityManager() != null) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null) { AccessController.doPrivileged((PrivilegedAction
作用:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能,指定组件在哪个环境的情况下才能被注册到容器中,不指定,则任何环境下都能注册这个组件。
备注:加了环境标识的bean,只有这个环境被激活时才能注册到容器中(默认是default环境)。
如,不同环境加载不同数据源(生产、开发、测试):
// 使用命令行动态参数,在虚拟机参数位置加(也可以在ApplicationContext中设置):-Dspring.profiles.active=test// 注册组件@Profile("test")@Bean("dataSource")public DataSource dataSourceTest() { ...}@Profile("dev")@Bean("dataSource")public DataSource dataSourceDev() { ...}@Profile("pro")@Bean("dataSource")public DataSource dataSourceProv() { ...}
需要注意以下两点:
BeanPostProcessor:前面我们介绍了BeanPostProcessor,它是一个bean的后置处理器,在bean创建对象的初始化前后进行拦截工作。
BeanFactoryPostProcessor:BeanFactory的后置处理器,在BeanFactory标准初始化之后调用,所有的Bean定义已经保存加载到BeanFactory中,但是还未执行Bean的实例化过程的时候执行。
和BeanPostProcessor一样,在refresh()中的invokeBeanFactoryPostProcessors(beanFactory)中,首先找到所有的BeanFactoryPostProcessor,并执行他们的方法。
@Componentpublic class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println(beanFactory); }}
它是BeanFactoryPostProcessor的子接口,在所有Bean定义信息将要被加载,但Bean实例还未创建的时候执行。
作用:优先于BeanFactoryPostProcessor执行,利用BeanDefinitionRegistryPostProcessor可以给容器中再额外添加一些组件,实例如下:
@Componentpublic class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { System.out.println("postProcessBeanDefinitionRegistry:当前bean数量:" + registry.getBeanDefinitionNames().length); // 添加组件 registry.registerBeanDefinition("color", new RootBeanDefinition(Color.class)); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("postProcessBeanFactory:当前bean数量:" + beanFactory.getBeanDefinitionNames().length); }}// 打印结果postProcessBeanDefinitionRegistry:当前bean数量:9postProcessBeanFactory:当前bean数量:10
原理:在refresh()方法中,调用 invokeBeanFactoryPostProcessors 方法,首先从容器中获取到所有的 BeanDefinitionRegistryPostProcessor 组件,再来依次触发所有的 postProcessBeanDefinitionRegistry() 方法,接着再来触发它们的 postProcessBeanFactory()方法。执行完这些之后,再从容器中找到BeanFactoryPostProcessor组件,然后依次触发postProcessBeanFactory()
源码:
while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); // 首先调用 invokeBeanDefinitionRegistryPostProcessors invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
介绍:Bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建Bean实例。
作用:监听容器中发布的事件,事件驱动模型开发。
// 监听ApplicationEvent 及其下面子事件@FunctionalInterfacepublic interface ApplicationListenerextends EventListener { ... }
步骤:
写一个监听器来监听某个事件,并注册到容器
@Componentpublic class TestApplicationListener implements ApplicationListener{ @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println(event); }}
只要容器中有相关事件的发布,我们就能监听到这个事件。
事件发布流程:
事件多播器(派发器):
容器中有哪些监听器:
容器创建对象:refresh()
registerListeners()
从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中
// 获取所有监听器String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);// 添加到派发器中for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}
作用:标注的方法在监听的事件发布时执行
基本使用:
@Repositorypublic class TestDao { @EventListener(classes = ApplicationEvent.class) public void listen() { System.out.println("监听...."); }}
原理:
附视频学习链接:https://www.bilibili.com/video/BV1oW41167AV
r;
容器中有哪些监听器:
容器创建对象:refresh()
registerListeners()
从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中
// 获取所有监听器String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);// 添加到派发器中for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}
作用:标注的方法在监听的事件发布时执行
基本使用:
@Repositorypublic class TestDao { @EventListener(classes = ApplicationEvent.class) public void listen() { System.out.println("监听...."); }}
原理:
附视频学习链接:https://www.bilibili.com/video/BV1oW41167AV
转载地址:http://wkprn.baihongyu.com/