参考视频网站:https://www.bilibili.com/video/BV1gW411W7wy?from=search&seid=4049766269580249763
Bean的创建过程:https://blog.csdn.net/z69183787/article/details/78415635
---
资料:
代码:
关于componentScan:https://www.jianshu.com/p/64aac6461d5b
代码在:
文章:https://www.jianshu.com/p/1dec08d290c1
BeanFactory和ApplicationAware的区别:https://blog.csdn.net/pythias_/article/details/82752881
------------------------------------------------------------------------
官方代码:
注解:
---02---
包扫描:如何定义包扫描
这个就是一般的扫描。
写几个bean
测试:
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
}
---
排除:按照注解
只包含:
一般的话包扫描就是你不new一个bean就是给你自动的扫描的,boot的扫描路径是默认的路径,你懂的。
---03---
自定义的规则。
//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则
package com.atguigu.config;
import java.io.IOException;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
public class MyTypeFilter implements TypeFilter {
/**
* metadataReader:读取到的当前正在扫描的类的信息
* metadataReaderFactory:可以获取到其他任何类信息的
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// TODO Auto-generated method stub
//获取当前类注解的信息 就是引用这个规则的类
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("er")){
return true;
}
return false;
}
}
---04---
单实例调用时机
多实例
多实例是懒加载的就是用的时候才加载的,就是getBean的时候才加载的。
---05---
单实例的懒加载
---06---
可以加在类上也可以加在方法上
写上两个类:
package com.atguigu.condition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
//判断是否linux系统
public class LinuxCondition implements Condition {
/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:注释信息
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO是否linux系统
//1、能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取当前环境信息
Environment environment = context.getEnvironment();
//4、获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
//可以判断容器中的bean注册情况,也可以给容器中注册bean
boolean definition = registry.containsBeanDefinition("person");
// if(property.contains("linux")){
// return true;
// }
if (definition) {
return true;
}
return false;
}
}
package com.atguigu.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
//判断是否windows系统
public class WindowsCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")){
return true;
}
return false;
}
}
---07---
如何使用@Import
只能再类上打印的。
@Test
public void test04(){
System.out.println("");
printBeans(applicationContext);
System.out.println("");
}
----------------------------------08----------------------------------
第二种用法:
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
//返回值,就是到导入到容器中的组件全类名
//AnnotationMetadata:当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// TODO Auto-generated method stub
//importingClassMetadata
//方法不要返回null值
return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
}
}
注意这个:AnnotationMetadata
----------------------------------09----------------------------------
第三种用法:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata:当前类的注解信息
* BeanDefinitionRegistry:BeanDefinition注册类;
* 把所有需要添加到容器中的bean;调用
* BeanDefinitionRegistry.registerBeanDefinition手工注册进来
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red");
boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
if(definition && definition2){
//指定Bean定义信息;(Bean的类型,Bean。。。)
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
//注册一个Bean,指定bean名
registry.registerBeanDefinition("rainBow", beanDefinition);
}
}
}
----------------------------------10----------------------------------
11.FactoryBean。
package com.atguigu.bean;
import org.springframework.beans.factory.FactoryBean;
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//是单例?
//true:这个bean是单实例,在容器中保存一份
//false:多实例,每次获取都会创建一个新的bean;
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
applicationContext就是一个容器罢了:
代码:
代码:
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//是单例?
//true:这个bean是单实例,在容器中保存一份
//false:多实例,每次获取都会创建一个新的bean;
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
在MainConfig2配置文件加入:
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
调用:
//工厂Bean获取的是调用getObject创建的对象
Object bean2 = applicationContext.getBean("colorFactoryBean");
Object bean3 = applicationContext.getBean("colorFactoryBean");
System.out.println("bean的类型:"+bean2.getClass());// 获取的是调用getObject方法创建的对象
System.out.println(bean2 == bean3);
Object bean4 = applicationContext.getBean("&colorFactoryBean");// 获取的是Factorybean
System.out.println(bean4.getClass());
获取:
--------------------------------------11-----------------------------------------
12.bean的生命周期
@Configuration和@Bean:https://blog.csdn.net/liuyinfei_java/article/details/82011805
可以在xml指定的。
1.构造器方法:是容器启动时候创建的
2.初始化方法:初始化完毕就调用init
3.销毁方法:容器关闭调用destory
-----------------------
多例的话获取才初始化init,但是不会销毁就是不会自动管理。
代码:
Bean生命周期,实例化,属性赋值,初始化,销毁。
@Component
public class Car {
public Car(){
System.out.println("car constructor...");
}
public void init(){
System.out.println("car ... init...");
}
public void detory(){
System.out.println("car ... detory...");
}
}
@ComponentScan("com.atguigu.bean")
@Configuration
public class MainConfigOfLifeCycle {
//@Scope("prototype")
@Bean(initMethod="init",destroyMethod="detory")
public Car car(){
return new Car();
}
}
public class IOCTest_LifeCycle {
@Test
public void test01(){
//1、创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成...");
//applicationContext.getBean("car");
//关闭容器
applicationContext.close();
}
}
-----------------------------------------------12----------------------------------------------------
13.
Initializing:
作用时机是把所有的属性设置好之后,会调用afterPropertiesSet方法。
DisposableBean:
这个是在for循环里面了
看下与后置处理器之间的关系。
调用时机:https://www.cnblogs.com/wz1989/p/4273480.html
第二种方法:
在beanFactory设置完所有bean之后属性赋值之后进行调用的,调用这个方法。
实现:
代码:
@Component
public class Cat implements InitializingBean,DisposableBean {
public Cat(){
System.out.println("cat constructor...");
}
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat...destroy...");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat...afterPropertiesSet...");
}
}
@ComponentScan("com.atguigu.bean")
@Configuration
public class MainConfigOfLifeCycle {
//@Scope("prototype")
@Bean(initMethod="init",destroyMethod="detory")
public Car car(){
return new Car();
}
}
public class IOCTest_LifeCycle {
@Test
public void test01(){
//1、创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成...");
//applicationContext.getBean("car");
//关闭容器
applicationContext.close();
}
}
----------------------------------------13-----------------------------------------
14.@PostConstruct和@PreDestory
第三种方法也是Bean创建完成并且属性值赋值完成:
在加载之后
在移除之前
总结:https://www.bbsmax.com/A/Gkz17VYN5R/
代码:
@Component
public class Dog implements ApplicationContextAware {
//@Autowired
private ApplicationContext applicationContext;
public Dog(){
System.out.println("dog constructor...");
}
//对象创建并赋值之后调用
@PostConstruct
public void init(){
System.out.println("Dog....@PostConstruct...");
}
//容器移除对象之前
@PreDestroy
public void detory(){
System.out.println("Dog....@PreDestroy...");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
this.applicationContext = applicationContext;
}
}
----------------------------------------14-----------------------------------------
15.BeanPostProcesser
后置处理器,每个bean
代码:
@Component
public class MyBeanPsotProcesser implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("post before"+ beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("post after" + beanName);
return bean;
}
}
代码:
在所有实例的初始化方法就是init不是构造之前和之后调用的。
测试结果:
-----------------------------------------------15-----------------------------------------
BeanPostProcesser的原理:
ApplicationRunner:https://blog.csdn.net/jdd92/article/details/81053404
总结:
1.创建ioc容器:
2.在构造方法里面:
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
3.进入这个方法
4.applicationContext调用的beanFactory
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有的单实例bean
beanFactory.preInstantiateSingletons();
初始化所有的单实例的bean。
5.在循环中getBean,doGetBean方法:createBean,doCreateBean。
6.创建对象
初始化是在属性赋值之后的。
populateBean就是先给属性赋值好。
然后进入initializeBean方法。
进入这个方法:
进入initializeBean
执行初始化方法就是init。
总结:
进入:
这里遍历所有的beanProcesser。一旦返回null直接跳出for循环。
Bean的生命周期:https://www.jb51.net/article/154487.htm
总的原理:
package com.atguigu.config;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import com.atguigu.bean.Car;
/**
* bean的生命周期:
* bean创建---初始化----销毁的过程
* 容器管理bean的生命周期;
* 我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
*
* 构造(对象创建)
* 单实例:在容器启动的时候创建对象
* 多实例:在每次获取的时候创建对象\
*
* BeanPostProcessor.postProcessBeforeInitialization
* 初始化:
* 对象创建完成,并赋值好,调用初始化方法。。。
* BeanPostProcessor.postProcessAfterInitialization
* 销毁:
* 单实例:容器关闭的时候
* 多实例:容器不会管理这个bean;容器不会调用销毁方法;
*
*
* 遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
* 一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
*
* BeanPostProcessor原理
* populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
* initializeBean
* {
* applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
* invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
* applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
*}
*
*
*
* 1)、指定初始化和销毁方法;
* 通过@Bean指定init-method和destroy-method;
* 2)、通过让Bean实现InitializingBean(定义初始化逻辑),
* DisposableBean(定义销毁逻辑);
* 3)、可以使用JSR250;
* @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
* @PreDestroy:在容器销毁bean之前通知我们进行清理工作
* 4)、BeanPostProcessor【interface】:bean的后置处理器;
* 在bean初始化前后进行一些处理工作;
* postProcessBeforeInitialization:在初始化之前工作
* postProcessAfterInitialization:在初始化之后工作
*
* Spring底层对 BeanPostProcessor 的使用;
* bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
*
* @author lfy
*
*/
@ComponentScan("com.atguigu.bean")
@Configuration
public class MainConfigOfLifeCycle {
@Scope("prototype")
@Bean(initMethod="init",destroyMethod="detory")
public Car car(){
return new Car();
}
}
--------------------------------------------16-----------------------------------------
spring底层:
作用是帮我们组件注入ioc容器的。
帮我们的注入IOC容器,想要什么就是Aware之前是什么。
例子1:这个就是通过后置处理器处理的。
public class Dog implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
源码:
ApplicaitonContextAware和ApplicationContextAwareProcesser关系
进入这个类看下下面的方法。
可以看到是在初始化之前调用的。
例子2:校验Bean。
例子3:@PostContust注解等
利用反射。
例子4:
总结:
看下在初始化之前之后调用的例子:
---------------------------------------------------------17----------------------------
package com.atguigu.bean;
import org.springframework.beans.factory.annotation.Value;
public class Person {
//使用@Value赋值;
//1、基本数值
//2、可以写SpEL; #{}
//3、可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值)
@Value("张三")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
private String nickName;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
}
}
---18-19---
自动装配:
---20---
---21---
不仅仅在属性上是可以装配的,在其它的地方也是可以装配的。
第一种set方法:
第二种在有参构造器:
第三种:放在参数位置,set何让构造都可以
第四种:只有一个有参构造器的话自动注入的注解可以省略的。
第五种在配置类里面:
可以省略的。
---22---
自定义的组件想使用spring的底层的一些组件。
实现一个
package com.atguigu.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;
@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
System.out.println("传入的ioc:"+applicationContext);
this.applicationContext = applicationContext;
}
public void setBeanName(String name) {
// TODO Auto-generated method stub
System.out.println("当前bean的名字:"+name);
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
// TODO Auto-generated method stub
String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
System.out.println("解析的字符串:"+resolveStringValue);
}
}
原理之前讲了。
---23---
package com.atguigu.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;
import com.atguigu.bean.Yellow;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* Profile:
* Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
* 开发环境、测试环境、生产环境;
* 数据源:(/A)(/B)(/C);
* @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
* 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
* 2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
* 3)、没有标注环境标识的bean在,任何环境下都是加载的;
*/
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
@Value("${db.user}")
private String user;
private StringValueResolver valueResolver;
private String driverClass;
@Bean
public Yellow yellow(){
return new Yellow();
}
@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("prod")
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");
dataSource.setDriverClass(driverClass);
return dataSource;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
// TODO Auto-generated method stub
this.valueResolver = resolver;
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
}
}
---24---
---25---
IOC面试题:https://blog.csdn.net/a745233700/article/details/80959716
-------------------------------------------------------------------26----------------------------
IOC的流程走一遍:
1.
2.
3.
4.
5.createBean:执行的是实现的InstationAwarepostProsesser。
6.
这里面分为三个阶段:
创建bean的实例。
初始化
6.进入populateBean找到InstationAwarepostProsesser之后的调用点
7.Aware的调用点两个调用点
8.生命周期的接口是在哪里调用的?在初始化方法里面
9.执行的顺序
小总结: