//1. 什么是bd 2. bd怎么定义
//2.scan 扫描器 可以扫描------>ScannedGenericBeanDefinition
//3.reader 读取器 可以读取------>AnnotatedGenericBeanDefinition
//4.MetadataReader
//5.beanFacoty和context的区别
//6.factorybean
//7.ExcludeFilter和IncludeFilter
之前我也说了Spring的大体流程,以及我也写了代码
Spring先根据构造方法构造出一个原生的类--------->@Autowired进行属性赋值---->初始化前---->初始化---->初始化后------>bean
如果初始化之后有aop的话 可能还会衍生出来一个代理对象
这节我们就说下Spring中的核心架构
beandefination bean的定义,Spring中用来描述Bean的组件,比如说
Spring中有很多方式去定义bean,在Spring中通常会有几种方式定义bean
1.<bean>标签
2.@bean注解
3.@Component(@Service @Controller)
这些都叫做声明式bean 我们还可以编程式定义bean
我们可以通过beanDefinition 设置某一个bean的属性,比如说
beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载
声明式和编程式的定义的bean都类似,通过<bean/>,@Bean,@Component等申明式方式所定义的Bean,最终都会被Spring解析为对应的BeanDefinition对象,并放入Spring容器中。
BeanDefinationReader 可以直接吧某个类转化为BeanDefination,并且会解析该类上的注解比如说@Lazy之类的
#比如说
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
annotatedBeanDefinitionReader.register(User.class);
System.out.println(context.getBean("user"));
有了这个BeanDefinationReader的话 我就可以吧一个类加载成为BeanDefination, 然后放到Spring容器中了
通过.
annotatedBeanDefinitionReader.register(User.class); 这个api, 吧一个类放入到构建成一个Srpingbean对象然后再放入容器中
ClassPathBeanDefinition Scanner 扫描器 他可以进行扫描 扫描一个路径,
对扫描的类进行解析 比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition.然后放到spring容器中
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.lvhao");
System.out.println(context.getBean("userService"));
beanDefination是一个接口 有几个实现类
GenericBeanDefinition,Spring中 一个普通的beanDefination的实现类
叫做 GenericBeanDefinition,
ScannedGenericBeanDefinition----->被扫描出来的beanDefination
AnnotatedGenericBeanDefinition--------> annotatedBeanDefinitionReader.register(通过reader.register()的类)
而他们都是我们的GenericBeanDefinition的子类
我们再来看下下beanFactory 以及 ApplicationContext
beanFactory是一个接口 支持有关bean获取的一些操作
也就是说 ApplicationContext 比beanFactory的功能更加强大一些
支持事件驱动,国际化等一些功能,以及一些环境变量的问题
MetadataReader、ClassMetadata、AnnotationMetadata
// spring用来解析类 继而封装成bd??? 用reader来读取class 构造读取器 然后
//classMetadata基于reader拿到元数据
SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
// 构造一个MetadataReader
MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.lvhao.UserService");
// 得到一个ClassMetadata,并获取了类名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName());
// 获取一个AnnotationMetadata,并获取类上的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
System.out.println(annotationType);
}
factorybean 本质是一个bean
# 我此时的orderService没有加@Component
@Component("LvHaoFactoryBean")
public class LvHaoFactoryBean implements FactoryBean {
// 呢么 orderService 仍然也是一个Bean
public Object getObject() throws Exception {
return new OrderService();
}
public Class<?> getObjectType() {
return OrderService.class;
}
}
但是当我从Spring中获取的时候就会获取到
实现 FactoryBean 的getObject中返回的类,
属于Spring的扩展点之一,通常是用来整合第三方框架用的,将第三方构建好的类通过该方式可以整合到spring容器中 比如说sqlsessionFactoryBean
通过mybatis构建好的sqlsession,交给Spring管理
7.ExcludeFilter和IncludeFilter
着2个filter主要是做扫描用的
# 我在扫描的时候 及时com.lvhao下有这个UserService并且加了@Component 我spring也不会吧他当作一个bean
@ComponentScan(value = "com.lvhao", excludeFilters =
扫描排除
{@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)})
@ComponentScan(value = "com.lvhao",
# 我在扫描的时候 你加入这个类上没有加@Component 我也会认为你是一个bean
includeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)})
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
csdn文章推荐受影响解决办法10个字10行
我们知道Spring容器启动的时候会干2件事情
第一件事情就是扫描
第二件事情就是创建非懒加载的单例bean
在spring容器刚开始就会有这个scanner
scanner.scan().. 完成扫描 我们现在先去看下他是怎么去扫描的 扫描结束后他是怎么去加载非懒加载的单例bean的
# 上述就是大概流程 我们看看他是怎么扫描 因为我的扫描器的主要功能就是吧扫描得到的bd放入到Spring容器中
扫描的逻辑就是解析com.lvhao 下面的class所有包含@Component的 我给放入到bdmap中
#扫描逻辑比如说我传入一个com.lvhao
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
#// 通过asm技术 在com.lvhao 下面找对应的bd 如果加了@Component 的话我认为他是一个bean
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
# 设置属性 是否是单例原型
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
#设置基础值 给这些bean 赋值默认
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析这些注解上面的属性 并且set到bd中
#处理Lazy,Primary,DependsOn,Role,Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
# 检查check是否名字重复 名字重复我就报错
if (checkCandidate(beanName, candidate)) {
# 封装bdholder然后用registry 进行注册到
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
##this.beanDefinitionMap.put(beanName, beanDefinition); 底层会调用这里吧当前这个bean放入到beanDefinationMap中
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
当我们扫描完成之后,我们就会去将这些bd开始初始化 生成非懒加载的单例beans
这里就开始进行初始化创建bean
暂且理解为doscan----->preInstantiateSingletons() 也就是扫描完毕之后就开始初始化创建bean
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
//遍历beanName
for (String beanName : beanNames) {
//(暂时忽略) Root做合并用的 xml中的<bean标签 有parent属性
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 这里就体现出来了 要创建非懒加载的单例bean 如果这个bean是单例的并且是非懒加载的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
/ 如果是一个实现了factoryBean
if (isFactoryBean(beanName)) {
// 创建该对象 创建完毕之后放入到 singletonObjects中
.. key 为beanName value 为当前beanDefination
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 如果是一个普通bean 我直接创建 创建完毕之后放入到单例池中
.. key 为beanName value 为当前beanDefination
getBean(beanName);
}
}
}
/// 在所有的单例bean都创建完毕之后
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
/// 看是否实现了SmartInitializingSingleton 这个接口 spring的扩展点之一
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
一个类如果实现了factoryBean 在spring初始化的时候
会创建 以beanName 为该bean的名字,bd 放入到单例池中
当我们 Object LvHaoFactoryBean = context.getBean("&LvHaoFactoryBean");
如果前面带& 会返回 factoryBean
如果不带& 会执行创建bean的逻辑---------->factory的getObject()方法
版权声明:本文为weixin_43689953原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。