spring底层自用学习笔记(一) BeanFactory与ApplicationContext

spring底层学习笔记(一) BeanFactory与ApplicationContext

课程:某站视频黑马程序员Spring视频教程,深度讲解spring5底层原理

0.环境准备-springboot项目搭建

这里用了aliyunstart使用git直接拉取demo代码

git clone "https://start.aliyun.com/type=maven-project&language=java&architecture=none&bootVersion=2.6.13&baseDir=demo&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&packaging=jar&javaVersion=1.8/demo.git" demo

1.BeanFactory与ApplicationContext的关系

在加有@SpringBootApplication注解的引导类的main方法中,SpringBootApplication.run()方法存在返回值(spring容器-ConfigurableApplicationContext)

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        //SpringBootApplication.run()方法存在返回值(spring容器-ConfigurableApplicationContext)
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
    }

}

对ConfigurableApplicationContext 使用快捷键ctrl+alt+u,查看类图
ConfigurableApplicationContext
可以看出二者的关系:ApplicationContext间接继承了BeanFactory,提供了功能上的扩展

2.BeanFactoryg功能

问题1.什么是BeanFactory?
ApplicationContext的父接口,它才是spring的核心容器,主要的ApplicationContext实现都组合了它的功能,BeanFactory是ApplicationContext的一个成员变量

这个context有getBean的方法,但实际还是使用的BeanFactory的getBean方法
getBean

问题2:BeanFactory什么用处?
表面上只有getBean,实际上控制反转、基本的依赖注入,直至Bean的什么周期的各种功能,都由它的实现类(DefaultListableBeanFactory)提供。
也就是说,DefaultListableBeanFactory才是真正实现了容器接口并可以独立使用的类,是IOC的核心

DefaultListableBeanFactory是一个重要的类,它可以管理所有bean,以及单例对象。
(选中DefaultSingletonBeanRegistry按F4跳转)
在这里插入图片描述
然后我们进入到DefaultSingletonBeanRegistry类中。
Spring的bean其实都是在这个类中被管理,二级缓存、三级缓存之类的其实是一个个不同功能的map。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

	/** Maximum number of suppressed exceptions to preserve. */
	private static final int SUPPRESSED_EXCEPTIONS_LIMIT = 100;


	/** Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

	/** Set of registered singletons, containing the bean names in registration order. */
	private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

	/** Names of beans that are currently in creation. */
	private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/** Names of beans currently excluded from in creation checks. */
	private final Set<String> inCreationCheckExclusions =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/** Collection of suppressed Exceptions, available for associating related causes. */
	@Nullable
	private Set<Exception> suppressedExceptions;

	/** Flag that indicates whether we're currently within destroySingletons. */
	private boolean singletonsCurrentlyInDestruction = false;

	/** Disposable bean instances: bean name to disposable instance. */
	private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

	/** Map between containing bean names: bean name to Set of bean names that the bean contains. */
	private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);

	/** Map between dependent bean names: bean name to Set of dependent bean names. */
	private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

	/** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
	private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

}

这里我们回到启动类,通过反射看一下singletonObjects这个map(包含所有的单例bean)

@SpringBootApplication
public class Application {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        //SpringBootApplication.run()方法存在返回值(spring容器-ConfigurableApplicationContext)
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

        //1.拿到私有的成员变量对象
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        //2.设置允许通过反射访问私有变量
        singletonObjects.setAccessible(true);
        //3.获取beanFactory-DefaultListableBeanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //4.反射调用-field.get(obj)返回指定对象obj上此field标识字段的值
        //也就是获取beanFactory中的singletonObjects对象
        Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        map.forEach((k,v)->{
            //这里输出的就是所有的单例bean
            System.out.println(k+"="+v);
        });
    }

}

这里context.getBeanFactory()获取到的其实是实现了ConfigurableListableBeanFactory接口的DefaultListableBeanFactory对象,而DefaultListableBeanFactory是DefaultSingletonBeanRegistry的子类,所以包含了父类的几个map,其中有我们需要的singletonObjects

debug看下这个map,里面就是所有的单例bean了。
在这里插入图片描述

3.ApplicationContext功能

ConfigurableApplicationContext
还是这张图,拓展的四个接口

/*
        2.ApplicationContext比BeanFactory多点啥
        */
        //1.国际化 实际应用中Locale这个参数是通过请求头带过来的
        System.out.println(context.getMessage("hi",null, Locale.CHINA));
        //2.获取资源
        Resource resource = context.getResource("classpath:application.yaml");
        System.out.println(resource);
        //使用通配符在所有jar包中找
        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for(Resource a : resources){
            System.out.println(a);
        }
        //3.获取配置信息,环境变量或配置文件
        System.out.println(context.getEnvironment().getProperty("java_home"));
        System.out.println(context.getEnvironment().getProperty("server.port"));
        //4.发布事件,spring自带mq,但只适用于单体应用,必须是同一个jvm,一个服务内部需要解耦的场景
        //中间件mq通常是跨服务的
        //这里应该是同步的,异步需要在方法上使用@Async注解,在启动类上要加@EnableAsync注解
        //context.publishEvent(new UserRegisterEvent(context));
        context.getBean(Component1.class).register();

配合@EventListener注解使用

@Component
public class Component2 {
    private static final Logger log = LoggerFactory.getLogger(Component2.class);

    //spring中的任何组件都可以作为监听器,入参的类型以发布事件类型为准
    @EventListener
    public void aaa(UserRegisterEvent event){
        log.debug("{}",event);
        log.debug("发送短信");
    }
}

总结:
(1)BeanFactory与ApplicationContext并不仅仅是简单接口继承的关系,ApplicationContext组合并扩展了BeanFactory的功能
(2)新一种代码间解耦途径

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值