黑马spring源码笔记1-3讲

spring源码

IOC

BeanFactory和ApplicationContext接口联系

BeanFactory是ApplicationContext的父接口,是spring的核心组成接口。ApplicationContext对BeanFactory进行了扩展,类图展示如下

在这里插入图片描述

beanFactory是ApplicationContext的一个成员变量,所以我们可以看出,ApplicationContext对象主要是对BeanFactory进行扩展

在这里插入图片描述

BeanFactory容器里面的管理单例对象,都存放在这个变量里面

在这里插入图片描述

BeanFactory初探

BeanFactory的接口定义如下

在这里插入图片描述

  • 从表面上来看,仅仅只是定义了一些getBean方法
  • 但是其实现类DefaultListableBeanFactory实现了控制反转,依赖注入已经bean的生命周期

在这里插入图片描述

ApplicationContext接口的扩展功能

在这里插入图片描述

  1. MessageSource接口

定义了国际化的功能

在这里插入图片描述

  1. ResoucePatternResolver接口

定义了对资源读取

在这里插入图片描述

  1. EnvironmentCapable接口

定义了对配置变量的存储信息

在这里插入图片描述

  1. ApplicationEvenrPublisher接口

消息发布与订阅相关功能,主要运用的是观察者模式

在这里插入图片描述

总结

  1. BeanFactory是ApplicationContext的父接口,是spring的核心组成接口

  2. 但是ApplicationContext并不只是简简单单的父子接口关系,而是组合关系

  3. ApplicationContext对BeanFactory进行了一系列的功能扩展

练习:分别使用AOP和消息订阅与发布来实现用户注册的短信发送功能

AOP实现短信发送功能
1. 首先在UserService接口中定义注册功能
2. 在UserService的实现中,实现接口定义的功能
3. 编写AOP功能,在AOP中实现短信发送功能
4. 测试功能代码
  1. UserService接口

public interface UserService {

    void register(User user); 
}
  1. 编写UserService的实现类
@Service
public class UserServiceImpl implements UserService {

    @Override
    public void register(User user) {
        System.out.println("查询user是否存在,若不存在便可注册");
        System.out.println("用户注册");
    }
}
  1. 通过AOP编写短信发送功能
@Aspect
@Component
public class RegisterAdvice {

    @Around("execution(* com.xuanxie.impl.*.*(..))") // 我放在impl包下,可以自己做修改
    public Object sendMessage(ProceedingJoinPoint pjp){
        System.out.println("准备执行注册功能");
        Object ret;
        try {
            ret = pjp.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        System.out.println("已完成注册服务,准备发送短信");
        return ret;
    }
}
  1. 编写测试代码
@SpringBootTest
class SpringIocApplicationTests {
    @Autowired
    private UserService userService;

    @Test
    void contextLoads() {
       userService.register(new User());
    }

}
消息订阅与发布实现短信发送功能
1. 首先在UserService接口中定义注册功能
2. 自定义事件RegisterEvent
3. 在UserService的实现中,实现接口定义的功能,同时发布消息
4. 定义监听类,在监听类中实现邮箱发送功能
5. 测试功能代码
  1. 首先在UserService接口中定义注册功能
public interface UserService {

    void register(User user);
}
  1. 自定义事件RegisterEvent
public class RegisterEvent extends ApplicationEvent {
    public RegisterEvent(Object source) {
        super(source);
    }
}
  1. 在UserService的实现中,实现接口定义的功能,同时发布消息
@Service
public class UserServiceListenerImpl implements UserService, ApplicationEventPublisherAware {
   private ApplicationEventPublisher applicationEventPublisher;
    @Override
    public void register(User user) {
        System.out.println("用户注册成功");
        applicationEventPublisher.publishEvent(new RegisterEvent("register"));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
  1. 定义事件监听器,在事件监听器中发送邮件
@Component
public class RegisterListener {

    @EventListener
    public void registerListener(RegisterEvent event){
        System.out.println("发送邮件给用户");
    }
}
  1. 测试代码
@SpringBootTest
class SpringIocApplicationTests {
    @Autowired
    private UserService userService;

    @Test
    void contextLoads() {
       userService.register(new User());
    }

}

容器的实现

BeanFactory的实现

DefaultListableBeanFactory

在BeanFactory的实现类里面,最重要是DefaultListableBeanFactory

1. 创建DefaultListableBeanFactory工厂。
2. 创建AbstractBeanDefinition 这里面说明一些bean的定义。
3. 把BeanFactory的后处理器注册到BeanFactory,为了之后方便的拿到BeanFactory的后处理器。
4. 通过调用BeanFactory后处理器的方法,把@bean等注解进行解析。如名字所说 它仅仅指挥处理BeanFactory相关的部分,也就是可以处理bean的定义相关,但是不能对依赖注入处理,例如:@Autowired,@Resource等等。(bean的定义包括:class,scope,初始化等等)
5. 通过把Bean后处理器注册到BeanFactory工厂当中,这样便可处理@Autowired,@Resource
6. 通过以上过程便可以创建bean对象并且有依赖注入的功能,但是此时对于单例bean的创建是在其调用的时候才创建而不是在工厂创建时创建,所以需要手动调用方法来实现单例bean的创建


- 个人感觉,每一个后处理器都是对BeanFactory的一个扩展,BeanFactory的后处理器是扩展了bean定义的功能,例如:可以通过@Bean来创建Bean对象。Bean的后处理器是扩展了bean创建的功能,例如:通过@Autowired注解实现依赖注入。
public class TestBeanFactory {
    public static void main(String[] args) {
        // 创建BeanFactory的实现类
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        // Bean的定义(class,scope,初始化。。。)
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config", beanDefinition);
        // 此时只会输出一个config,因为现在beanFactory并没有解析@Bean注解
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println("name = " + name);
        }
        System.out.println("--------------------------");

        // 给BeanFactory的后处理器,补充一些bean的定义 此时只是后处理器只是存在于BeanFactory当中,并没有与bean的创建产生联系
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

        // 此时的输出会多出一些常用的后处理器,但是bean1和bean2并不会创建
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println("name = " + name);
        }
        System.out.println("--------------------------");
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class)
            	.values()
                .forEach(beanFactoryPostProcessor -> beanFactoryPostProcessor.postProcessBeanFactory(beanFactory));
        // 此时bean1和bean2也会输出,但是依赖注入功能没有实现,从bean1中并不会获得bean2
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println("name = " + name);
        }
        System.out.println("--------------------------");

        // Bean后处理器,针对bean的生命周期各个阶段提供扩展,例如@Autowired @Resource ...
        beanFactory.getBeansOfType(BeanPostProcessor.class)
            	.values()
        //     通过这一步可以bean的创建与bean后处理器产生联系
                .forEach(beanFactory::addBeanPostProcessor); // ==>.forEach(beanPostProcessor -> beanFactory.addBeanPostProcessor(beanPostProcessor));
        // 此时我们可以发现单例的bean创也建是在使用的时候再创建而不是在工厂创建的时候创建
//        System.out.println("--------------------------");
//        System.out.println(beanFactory.getBean("bean1"));
        // 为了让单例bean不是在使用的时候创建,我们需要使用 beanFactory.preInstantiateSingletons();来创建单例bean对象
        beanFactory.preInstantiateSingletons();
        System.out.println("--------------------------");
        System.out.println(beanFactory.getBean("bean1"));
        /*
            beanFactory不会做的事情
             1. 不会主动调用BeanFactory后处理器
             2. 不会主动调用Bean后处理器
             3. 不会主动创建单例对象
             4. 不会解析#{}, ${}
         */
    }

    @Configuration
    static class Config{
        @Bean
        public Bean1 bean1(){
            return new Bean1();
        }
        @Bean
        public Bean2 bean2(){
            return new Bean2();
        }
    }

    static class Bean1{


        @Autowired
        private Bean2 bean2;

        public Bean1(){
            System.out.println("Bean1.Bean1");
        }

        public Bean2 getBean2() {
            return bean2;
        }

    }
    static class Bean2{
        public Bean2(){
            System.out.println("Bean2.Bean2");
        }
    }
}

ApplicationContext的实现

1. ClassPathXmlApplicationContext和FileSystemXmlApplicationContext都是通过读取xml来获取BeanDefinition,之后更具BeanFactory来创建Bean
	- 具体过程
		1. 创建BeanFactory
		2. 创建xmlBeanDefinitionReader,构造函数的参数是解析xml的BeanDefinition放置位置
		3. 传入带解析的xml文件(可以选择ClassPathResource解析也可以选择FileSystemResource解析)
		4. 通过这种方式,并不会注入BeanFactory的后处理器,除非在xml配置文件中添加<context:annotation-driven/>

1.ClassPathXmlApplicationContext

ClassPathXmlApplicationContext 当我们初学的时候,都是学习该类去实现spring。现在我们再来回顾一下简单使用

public class TestApplicationContext {
    public static void main(String[] args) {
		 // 与FileSystemXmlApplicationContext的最大区别就是路径不同,这里是从类路径读取文件,FileSystemXmlApplicationContext是从磁盘路径读取文件
        ApplicationContext applicationContext =  new ClassPathXmlApplicationContext("b01.xml");
        Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");
        System.out.println("------------------------");
        System.out.println(bean1.getBean2());
    }
}
<!-- spring配置文件-->
<?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="bean1" class="com.xuanxie.spring_ioc.TestApplicationContext.Bean1">
        <property name="bean2" ref="bean2"/>
    </bean>
    <bean id="bean2" class="com.xuanxie.spring_ioc.TestApplicationContext.Bean2"/>
</beans>

2.FileSystemXmlApplicationContext

FileSystemXmlApplicationContext和FileSystemXmlApplicationContext很类似,我们先来看看它的用法

// java文件
public class TestApplicationContext {
    public static void main(String[] args) {
        // 与ClassPathXmlApplicationContext的最大区别就是路径不同,这里是从磁盘读取文件,ClassPathXmlApplicationContext是从类路径读取文件
        ApplicationContext applicationContext =  new FileSystemXmlApplicationContext("E:\\spring_konw_about\\spring_ioc\\src\\main\\resources\\b01.xml"); 
        Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");
        System.out.println("------------------------");
        System.out.println(bean1.getBean2());
    }
}
<!-- spring配置文件-->
<?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="bean1" class="com.xuanxie.spring_ioc.TestApplicationContext.Bean1">
        <property name="bean2" ref="bean2"/>
    </bean>
    <bean id="bean2" class="com.xuanxie.spring_ioc.TestApplicationContext.Bean2"/>
</beans>

1和2总结

// 模拟实现
public class TestApplicationContext {
    public static void main(String[] args) {
		// 1.创建beanFactory
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		// 2.创建xmlBeanDefinitionReader,并将BeanDefinition放置beanFactory中
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        // 3.通过FileSystemResource或者ClassPathResource读取xml并解析成BeanDefinition,并将其加载到beanFactory
        xmlBeanDefinitionReader.loadBeanDefinitions(new FileSystemResource("b01.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println("name = " + name);
        }
    }
}

3.AnnotationConfigApplicationContext

AnnotationConfigApplicationContext的基本使用,我们通过输出可以发现BeanFactory的后处理器已经自动添加上去了,同时把Config也作为Bean添加到容器当中

public class TestApplicationContext {
    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        for (String name : applicationContext.getBeanDefinitionNames()) {
            System.out.println("name = " + name);
        }
    }

    @Configuration
    static class Config{
        @Bean
        public Bean1 bean1(){
            return new Bean1();
        }
        @Bean
        public Bean2 bean2(){
            return new Bean2();
        }
    }

    static class Bean1{


        public void setBean2(Bean2 bean2) {
            this.bean2 = bean2;
        }

        @Autowired
        private Bean2 bean2;

        public Bean1(){
            System.out.println("Bean1.Bean1");
        }

        public Bean2 getBean2() {
            return bean2;
        }

    }
    static class Bean2{
        public Bean2(){
            System.out.println("Bean2.Bean2");
        }
    }
}

4.AnnotationConfigServletWebServerApplicationContext

  1. 创建Tomcat服务器
  2. 创建DispatchServlet
  3. 把DispatchServlet和Tomcat联系起来
public class TestApplicationContext {
    public static void main(String[] args) {

        AnnotationConfigServletWebServerApplicationContext applicationContext = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);

    }

   @Configuration
    static class WebConfig{
        /*
            1. 创建Tomcat服务器
            2. 创建DispatchServlet
            3. 把DispatchServlet和Tomcat联系起来
         */
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            // 创建一个Tomcat的服务器实现
            return new TomcatServletWebServerFactory();
        }

        @Bean
        public DispatcherServlet dispatcherServlet(){
            return new DispatcherServlet();
        }

        @Bean
       public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet){
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }

        @Bean("/hello")
       public Controller controller(){
            return ((request, response) -> {
                response.getWriter().print("hello");
                return null;
            });
        }

   }
}

Bean的生命周期和模板设计模式

Bean的生命周期

Bean的生命周期一共有4个阶段如下
1. 构造方法
2. 依赖注入
3. 初始化
4. 销毁
// LifeCycleBean.java
@Component
public class LifeCycleBean {

    public LifeCycleBean() {
        System.out.println("构造方法=>LifeCycleBean.LifeCycleBean");
    }


    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String home){
        System.out.println("依赖注入=>home = " + home);
    }

    @PostConstruct
    public void init(){
        System.out.println("初始化=>LifeCycleBean.init");

    }

    @PreDestroy
    public void destroy(){
        System.out.println("销毁方法=>LifeCycleBean.destroy");
    }
}
// SpringIocApplication.java
@SpringBootApplication
public class SpringIocApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = SpringApplication.run(SpringIocApplication.class);
        context.close();
    }

}

Bean后处理器

1. Bean的后处理器主要是对Bean的生命周期过程做适当的扩充
	1. 构造阶段
		- 构造之前
		- 构造之后
	2. 注入阶段
		- 依赖注入之前
	3. 初始化阶段
		- 初始化之前
		- 初始化之后
    4. 销毁阶段
    	- 销毁之前
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {

   

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")){
            System.out.println("构造方法之前=>postProcessBeforeInstantiation,这里的返回对象会替换原来的Bean对象");
        }
        return null;
    }



    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")){
            System.out.println("构造方法之后=>postProcessAfterInstantiation,如果返回值是false那么会跳过注入阶段");
        }
        return true;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")){
            System.out.println("依赖注入阶段之前执行方法=>postProcessProperties,@Autowired,@Value注解都是在该阶段执行");
        }
        return pvs;
    }




    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")){
            System.out.println("初始化方法之前=>postProcessBeforeInitialization,返回值会替换掉原来的bean对象,@PostConstruct,@Configuration注解都是在该阶段执行");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")){
            System.out.println("初始化方法之后=>postProcessAfterInitialization,返回值会替换掉原来的bean对象,aop代理增强在该阶段执行");
        }
        return bean;
    }
    @Override
    public void postProcessBeforeDestruction(Object o, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")){
            System.out.println("销毁方法执行之前=>postProcessBeforeDestruction,如@PreDestory");
        }
    }

}

模板设计模式

在模板设计模式当中,里面会有变得量也会有不变的量的。不变的那部分相当于我们必走的流程。变的那部分相当于我们可以对其过程的一些扩展方法

1. 定义固定的过程
2. 定义接口方法
3. 创建接受接口变量的集合,并将接口方法运行到固定过程的位置,可能在某个步骤之后,也有可能在某个步骤之前
4. 创建添加接口实现的方法
5. 代码测试
public class templateThink {
    public static void main(String[] args) {
        MyBeanFactory beanFactory = new MyBeanFactory();
        beanFactory.getBean();
        System.out.println("-----------------------");
        beanFactory.addBeanPostProcessor(bean -> System.out.println("通过Bean后处理器添加的方法,运行在初始化方法之前"));
        beanFactory.getBean();
    }
    static class MyBeanFactory{

        private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
        public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
            this.beanPostProcessors.add(beanPostProcessor);
        }

        public Object getBean(){
        /*
            下面这是一个模板,任何一个类都需要经过下面的过程,
            如果不采用任何设计模式,那么我们当需要在依赖注入的时候做一些事情,
            我们要去修改下面的代码,但是对于程序设计来说,应该是更多的开放扩展而少修改
            定义了一个接口BeanPostProcessor,并在该类中的所有该接口的实现,都会添加到初始化方法之前
         */
            Object bean = new Object();

            System.out.println("构造方法执行");
            System.out.println("依赖注入执行");
            beanPostProcessors.forEach((beanPostProcessor -> beanPostProcessor.inject(bean)));
            System.out.println("初始化方法执行");
            System.out.println("销毁方法执行");
            return bean;
        }
    }
    static interface BeanPostProcessor{
        public void inject(Object bean);
    }
}


static Object getBean(){
        /*
            下面这是一个模板,任何一个类都需要经过下面的过程,
            如果不采用任何设计模式,那么我们当需要在依赖注入的时候做一些事情,
            我们要去修改下面的代码,但是对于程序设计来说,应该是更多的开放扩展而少修改
            定义了一个接口BeanPostProcessor,并在该类中的所有该接口的实现,都会添加到初始化方法之前
         */
            Object bean = new Object();

            System.out.println("构造方法执行");
            System.out.println("依赖注入执行");
            beanPostProcessors.forEach((beanPostProcessor -> beanPostProcessor.inject(bean)));
            System.out.println("初始化方法执行");
            System.out.println("销毁方法执行");
            return bean;
        }
    }
    static interface BeanPostProcessor{
        public void inject(Object bean);
    }
}

https://www.bilibili.com/video/BV1P44y1N7QG?p=1&vd_source=1c086e1d8d38cbdc5f4144e6a649f07f


版权声明:本文为weixin_45054622原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。