1 Spring整合Java 核心API

Java语言的变化
2004年:jdk5提供的枚举类、泛型、注解、拆箱和装箱
2006年:6提供的@Override接口
2011年:钻石语法、多个catch、try
2014年:lambda语法、可重复注解、类型注解
2017年:模块化、接口私有方法
2018年:局部变量类型推断

7提供的钻石语法、Spring支持5.0+,代表实现DefaultListableBeanFactory
try-with-resource语法、Spring支持5.9、ResourceBundle
8提供的Lambda语法

JDK核心API的部分
5之前的版本:反射、JavaBeans、动态代理
5的版本:J.U.C、Formater、Java管理扩展(JMX)、Instrumentation、XML处理
6的版本:JDBC4.0、JAXB2.0、可插拔的注解处理API
7的版本:NIO2、Fork/Join框架、invokedynamic字节码
8的版本:Stream API、CompletableFuture、Annotation on Java Types、Date and Time API、可重复Annotations、JavaScirpt运行时。
9的版本:Reactive Streams Flow API、varable Handlers、Method Handles、spi-wait Hints、stack-walking

python 小马哥 小马哥java_java

python 小马哥 小马哥java_java_02


注解的实现两种方式:第一就是ASM、第二就是Java的反射。都是在Java运行时进行实现

@Indexed实现可插拔的注解处理API

python 小马哥 小马哥java_User_03

2 Spring对JavaEE API整合

python 小马哥 小马哥java_python 小马哥_04

3 Spring实现的五种编程模型

  1. 面向对象编程(契约接口)
    契约接口
  • Aware接口,它是一种模式
    子接口有ApplicationContextAware,通过set接口把对应的前缀的类传递过来
    beanFactoryAware也是一样的接口
  • BeanPostProcessor

设计模式
观察者模式:ApplicationListener接口中onApplicatinEvent通过事件的方式,实现广播

组合模式:Composite…类

模版模式:如JdbcTemplate,

大量的Abstract*

  1. 面向切面编程(动态代理和字节码提升)
  • 动态代理的实现JdkDynamicAopProxy、AopProxy接口
  1. 面向元编程(配置元信息、注解、)
    注解:模式注解(@Component、@Service、@Respository)
    配置:Enviroment抽象、PropertySources、BeanDefinition
    泛型:GenericTypeResolve、ResovleType(简化泛型处理)
  2. 函数驱动:(lambda和Reactive)
    ApplicatinEvent
    FunctionalIntegerface
    Reactive(Mono和Flux)、Spring WebFulx
  3. 模块驱动
    Maven Artifacts、
    Spring的@Enable*

4 Spring的核心价值(比较重要)

  1. API抽象设计:AOP抽象、事务抽象、Environment抽象、生命周期
  2. 编程模型(看上面):OOP、面向切面、面向元编程、面向模块
  3. 设计思想:OOP、IOC/ID、DDD(领域驱动设计)、TDD(测试驱动)、EDP(事件驱动)、FP(函数驱动)
  4. 设计模式:专属模式+GOF23
    专属模式包含前缀模式(Enable模式+Configurable模式),后缀模式(处理器模式(Processor+Resolve+Handler)、意识模式(Aware)、配置器模式(Configuror)、选择器模式(importSelector))

5 Spring面试题目

  1. SpringFramework的核心模块?
    答:Spring Core基础API模块、如资源管理、泛型处理
    Spring bean:Spring Bean相关,如依赖查找、依赖注入
    Spring Aop:Spring AOP处理,如动态代理、AOP字节码提升
    Spring Context:事件驱动(ApplicationEvent)、注解驱动、模块驱动
    Spring expression:Spring表达式语言模块
  2. Spring Framework的优势和不足是什么?

6 Spring IoC(inversion of control)

知识点:IoC发展、IoC主要实现策略、IoC容器的职责、IoC容器的实现、传统IoC容器实现、轻量级IoC容器、依赖查找VS.依赖注入
构造器注入 VS. Setter注入

6.1 IoC主要实现策略(依赖查找和依赖注入)

  1. 使用service locator pattern
    **2. 依赖注入:构造器注入、属性注入、setter方法注入、
  2. 上下文查找contextualized lookup,**
  3. 使用模版方法模式
  4. 使用策略模式

6.2 IoC容器的职责

依赖处理:依赖查找和依赖注入。依赖怎么来的?怎么把它进行返回给客户端
生命周期:容器、托管的资源(bean或者其他资源比如事件)
配置:容器、外部化配置(属性配置等)、托管的资源(bean或者其他资源比如线程池)

6.3 IoC容器的实现

JavaSE:Java beans、Java ServiceLader SPI、JNDI(Java命名目录接口)
Java EE:EJB、Servlet
开源:Apache Avalon(依赖查找)、PicoContainer()、Google Guice(依赖注入和依赖查找)、SpringFramework

6.4 传统的IoC容器的实现

Java Bean作为IoC容器特性:依赖查找、生命周期管理、配置元信息、事件、自定义、资源管理、持久化
依赖查找
🐴【代码实例6-4-1】

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class); // 获取Java bean的信息
Stream.of(beanInfo.getPropertyDescriptors()).forEach(
        propertyDescriptor -> {
            System.out.println(propertyDescriptor);
        }
);
// 输出
java.beans.PropertyDescriptor[name=age; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@29774679; required=false}; propertyType=class java.lang.Integer; readMethod=public java.lang.Integer myspring.Person.getAge(); writeMethod=public void myspring.Person.setAge(java.lang.Integer)]
java.beans.PropertyDescriptor[name=class; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@3ffc5af1; required=false}; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()]
java.beans.PropertyDescriptor[name=name; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@5e5792a0; required=false}; propertyType=class java.lang.String; readMethod=public java.lang.String myspring.Person.getName(); writeMethod=public void myspring.Person.setName(java.lang.String)]

🐴【代码实例6-4-2】

// 使用PropertyEditor实现属性类型转换
 Person p = new Person();
Stream.of(beanInfo.getPropertyDescriptors()).forEach(
         propertyDescriptor->{
//                    System.out.println(propertyDescriptor);
             //PropertyDescriptor 运训添加属性编辑器 PropertyEditor
             Class<?> propertyType = propertyDescriptor.getPropertyType();
             String propertyName = propertyDescriptor.getName();
             if("age".equals(propertyName)){
                 //把string -> Integer Integer.valueOf("")
                 propertyDescriptor.setPropertyEditorClass(StringToIntegerProEditor.class);
                 propertyDescriptor.createPropertyEditor(p);

             }

         }
);
static class StringToIntegerProEditor extends PropertyEditorSupport{
    public void setAsText(String text) throws java.lang.IllegalArgumentException{
         Integer value = Integer.valueOf(text);
         setValue(value);
     }
}

6.5 轻量级IoC容器

6.6 依赖查找 VS. 依赖注入

python 小马哥 小马哥java_User_05

6.7 构造器注入 VS. Setter注入

SpringFrameWork对构造器注入于setter注入的论点:

  1. 提倡构造器注入,因为可以用一个不可变得对象传入构造器中,确保依赖不是null,其次构造器注入能够保证client调用是初始化了的对象。
  2. setter注入是一种可选的注入。@Autowire

setter注入的优点:支持JavaBean支持IDEs、JavaBean的属性是self-documenting。许多已经存在的JavaBeans能够在面向JavaBean的IoC容器中使用,不需要修改。
缺点:set的顺序不能确定,构造器的顺序是确定的。
org。springframework.beans.factory.InitializingBean接口保证了初始化调用任何一个初始化方法

6.8 面试题

  1. 什么是IoC

控制反转:好莱坞原则、依赖注入和依赖查找实现

Servlet也是一种IoC,可以通过外部依赖或者JNDI方式获取外部资源,包括DataSource或者EJB相关的组件。反向观察者模式也是一种IoC

  1. 依赖查找和依赖注入
    依赖查找:它的大体思路是容器中的受控对象通过容器的 API 来查找自己所依赖的资源和协作对象。这种方式虽然降低了对象间的依赖,但是同时也使用到了容器的 API,造成了我们无法在容器外使用和测试对象。依赖查找是一种更加传统的 IOC 实现方式。

依赖注入:自动注入基于构造器、setter方法注入,非自动注入基于属性注入。

  1. Spring作为IoC容器有什么优势?
    典型的IoC管理,依赖查找和依赖注入、AOP抽象、事务抽象、事件机制、SPI扩展、强大的第三方整合、容易测试性(Spring-test、spring-mock)、更好的面相对象

6.9 Spring IoC的依赖查找

实时查找和延时查找的区别:延时查找通过ObjectFactory获取bean,让applicatincontext加载完成,防止有些bean是null导致NPE问题。

Object Bean和FactoryBean的区别?
FactoryBean的使用案例:
FactoryBean只是一个接口,要创建工厂bean,你只需要把创建的bean类实现FactoryBean接口,该类将创建实际所需要的bean。简单起见,您可以扩展AbstractFactoryBean类。

根据Bean名称查找:实时查找和延时查找
根据Bean类型查找:单个Bean对象、集合Bean对象
根据Bean名称 + 类型查找
根据注解查找:单个Bean对象和集合Bean对象

🐴【代码实例6-9-1】

public static void main(String[] args) {
   // 配置 XML 配置文件
    // 启动 Spring 应用上下文
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
    // 按照类型查找
    lookupByType(beanFactory);
    // 按照类型查找结合对象
    lookupCollectionByType(beanFactory);
    // 通过注解查找对象
    lookupByAnnotationType(beanFactory);
	// 实时查找
    lookupInRealTime(beanFactory);
    // 延时查找
    lookupInLazy(beanFactory);
}

private static void lookupByAnnotationType(BeanFactory beanFactory) {
   if (beanFactory instanceof ListableBeanFactory) {
       ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
       Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
       System.out.println("查找标注 @Super 所有的 User 集合对象:" + users);
   }
}

private static void lookupCollectionByType(BeanFactory beanFactory) {
    if (beanFactory instanceof ListableBeanFactory) {
        ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
        Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
        System.out.println("查找到的所有的 User 集合对象:" + users);
    }
}
private static void lookupByType(BeanFactory beanFactory) {
    User user = beanFactory.getBean(User.class);
    System.out.println("实时查找:" + user);
}
private static void lookupInLazy(BeanFactory beanFactory) {
    ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
    User user = objectFactory.getObject();
    System.out.println("延迟查找:" + user);
}
private static void lookupInRealTime(BeanFactory beanFactory) {
    User user = (User) beanFactory.getBean("user");
    System.out.println("实时查找:" + user);
}

6.10 Spring IoC依赖注入

util:list手动配置
自动配置:auto-wiring
根据Bean名称注根据Bean类型注入:单个Bean对象、集合Bean对象
注入容器内建Bean对象
注入非Bean对象
注入类型:实时注入和延迟注入

🐴【代码实例6-10-1】

// UserRepository
public class UserRepository {

    private Collection<User> users; // 自定义 Bean

    private BeanFactory beanFactory; // 內建非 Bean 对象(依赖)

    private ObjectFactory<ApplicationContext> objectFactory;

    public Collection<User> getUsers() {
        return users;
    }

    public void setUsers(Collection<User> users) {
        this.users = users;
    }


    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }

    public ObjectFactory<ApplicationContext> getObjectFactory() {
        return objectFactory;
    }

    public void setObjectFactory(ObjectFactory<ApplicationContext> objectFactory) {
        this.objectFactory = objectFactory;
    }
}

// 主类
 public static void main(String[] args) {
  // 配置 XML 配置文件
    // 启动 Spring 应用上下文
//        BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");

    // 依赖来源一:自定义 Bean
    UserRepository userRepository = applicationContext.getBean("userRepository", UserRepository.class);

//        System.out.println(userRepository.getUsers());

    // 依赖来源二:依赖注入(內建依赖)
    System.out.println(userRepository.getBeanFactory());
    ObjectFactory userFactory = userRepository.getObjectFactory();
    System.out.println(userFactory.getObject() == applicationContext);
    // 依赖查找(错误)
//        System.out.println(beanFactory.getBean(BeanFactory.class));

    // 依赖来源三:容器內建 Bean
    Environment environment = applicationContext.getBean(Environment.class);
    System.out.println("获取 Environment 类型的 Bean:" + environment);
}
 private static void whoIsIoCContainer(UserRepository userRepository, ApplicationContext applicationContext) {
  // ConfigurableApplicationContext <- ApplicationContext <- BeanFactory
  // ConfigurableApplicationContext#getBeanFactory()
  // 这个表达式为什么不会成立 System.out.println(userRepository.getBeanFactory() == beanFactory); 因为ApplicationContext的实现类AbstractRefreshableApplicationContext中是通过组合的方式DefaultListableBeanFactory beanFactory,所以这里是False
  System.out.println(userRepository.getBeanFactory() == applicationContext); // True
// ApplicationContext is BeanFactory
}

6.11 Spring IoC依赖来源

自定义的Bean、容器内建Bean对象、容器内建依赖(比如Envirment)代码见上面

6.12 Spring IoC配置元信息

bean定义配置:基于XML文件、基于Properties文件、基于Java注解、基于Java API
IoC容器配置:基于XML文件、基于Java注解、基于Java API
外部化属性配置:基于Java注解

6.13 Spring IoC容器

BeanFactory和ApplicationContext谁才是IoC容器?
ApplicationContext是BeanFactory的sub-interface,提供了Spring的AOP特征更好的集成,
消息资源处理、事件发布、应用层级别特殊的contexts
ApplicationContext是BeanFactory的子集,组合了 BeanFacotry

6.14 Spring应用上下文

ApplicationContext除了IoC容器角色,还提供了
AOP、配置元信息(Environments)、资源管理(Resources)、事件、国际化、注解、Envirnmnet抽象(配置走profile、外部化配置)

6.15 使用Spring IoC:选BeanFactory还是ApplicationContext

使用BeanFactory

使用ApplicationContext

6.16 Spring IoC容器的生命周期

启动

application.refresh()—> 加锁startupShudownMonitor–》prepareRefresh
 —〉refreshBeanFactory(对beanFactoryMonitory加把锁)
 initMessageSource应用程序国际化
 initApplicationEventMulticaster事件广播

运行

停止
application.close()—>doclose()
销毁bean、销毁BeanFactory

6.17 面试题目

  1. 什么是Spring IoC容器?
  2. BeanFactory和FactroyBean区别?
    BeanFactory是IoC底层容器,FactoryBean是创建Bean的一直方式,帮助实现复杂的Bean初始化过程

但是在某些具体的情况下,实例化 Bean 的操作会很复杂,按照其要求需要配置大量的属性,此时 Bean 的配置灵活性就受到了限制,此时就需要使用到 FactoryBean 了,该接口可以按照用户的需求来构造 Bean 对象,而不再遵守 Bean 生命周期的流程

  1. Spring IoC容器启动时候做了哪些准备?
    IoC配置元信息读取和解析、IoC容器生命周期、Spring事件发布、国际化等

7 Spring Bean 基础

定义SPring Bean、BeanDefinition元信息、命名Spring bean、实例化Spring Bean、初始化Spring Bean、延迟初始化Spring Bean、销毁Spring Bean、垃圾回收Spring Bean

7.1 定义 Spring Bean

BeanDefinition 是Spring Framework 中定义 Bean 的配置元信息接口,包括:

  • Bean 的类名
  • Bean 行为配置元素,如作用域、自动绑定的模式、生命周期回调等
  • 其他 Bean 引用,依赖关系
  • 配置设置,比如 Bean 属性 (Properties

7.2 BeanDefinition 元信息

python 小马哥 小马哥java_java_06


BeanDefinition 的构建

  1. 通过Builder模式,使用BeanDefinitionBuilder
  2. 通过AbstractBeanDefinition,直接使用GenericBeanDefinition extends AbstractBeanDefinition
public static void main(String[] args) {
   // 1.通过 BeanDefinitionBuilder 构建
   BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
   // 通过属性设置
   beanDefinitionBuilder
           .addPropertyValue("id", 1)
           .addPropertyValue("name", "小马哥");
   // 获取 BeanDefinition 实例
   BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
   // BeanDefinition 并非 Bean 终态,可以自定义修改

   // 2. 通过 AbstractBeanDefinition 以及派生类
   GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
   // 设置 Bean 类型
   genericBeanDefinition.setBeanClass(User.class);
   // 通过 MutablePropertyValues 批量操作属性
   MutablePropertyValues propertyValues = new MutablePropertyValues();
//        propertyValues.addPropertyValue("id", 1);
//        propertyValues.addPropertyValue("name", "小马哥");
   propertyValues
           .add("id", 1)
           .add("name", "小马哥");
   // 通过 set MutablePropertyValues 批量操作属性
   genericBeanDefinition.setPropertyValues(propertyValues);
}

7.3 命名 Spring Bean

python 小马哥 小马哥java_python 小马哥_07


Bean 名称生成器(BeanNameGenerator)

DefaultBeanNameGenerator:默认通用 BeanNameGenerator 实现

AnnotationBeanNameGenerator:基于注解扫描的 BeanNameGenerator 实现

7.4 Spring bean 别名化

Bean 别名(Alias)的价值

  • 复用现有的 BeanDefinition
  • 更加具有场景化的命名方法,通过<alias name=“原先 bean 的名称” alias=“新的别名”>
  1. 配置文件
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 导入第三方 Spring XML 配置文件 -->
    <import resource="classpath:/META-INF/dependency-lookup-context.xml" />

    <!-- 将 Spring 容器中 "user" Bean 关联/建立别名 - "xiaomage-user" -->
    <alias name="user" alias="xiaomage-user" />
</beans>
  1. Java 代码
public class BeanAliasDemo {

    public static void main(String[] args) {
        // 配置 XML 配置文件
        // 启动 Spring 应用上下文
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definitions-context.xml");
        // 通过别名 xiaomage-user 获取曾用名 user 的 bean
        User user = beanFactory.getBean("user", User.class);
        User xiaomageUser = beanFactory.getBean("xiaomage-user", User.class);
        System.out.println("xiaomage-user 是否与 user Bean 相同:" + (user == xiaomageUser));
    }
}

7.5 注册 Spring Bean,把 BeanDefinition 注册到IoC容器中

BeanDefinition 注册

  • XML 配置元信息
  • Java 注解配置元信息@Bean、@Component、@Import
  • Java API 配置元信息
    命名方式:BeanDefinitionRegistry#registerBeanDefiniiton(String, BeanDefinition)
    非命名方式:BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition, BeanDefinitionRegistry)
    配置类方式:AnnotatedBeanDefinitionReader#registrer(Class…)
@Import(AnnotationBeanDefinitionDemo.Config.class)
public class AnnotationBeanDefinitionDemo {
	public static void main(String[] args) {
	   // 创建 BeanFactory 容器
	   AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
	   // 注册 Configuration Class(配置类)
	   applicationContext.register(AnnotationBeanDefinitionDemo.class);
	   // 通过 BeanDefinition 注册 API 实现
	   // 1.命名 Bean 的注册方式
	   registerUserBeanDefinition(applicationContext, "mercyblitz-user");
	   // 2. 非命名 Bean 的注册方法
	   registerUserBeanDefinition(applicationContext);
	   // 启动 Spring 应用上下文
	   applicationContext.refresh();
	   // 按照类型依赖查找
	   System.out.println("Config 类型的所有 Beans" + applicationContext.getBeansOfType(Config.class));
	   System.out.println("User 类型的所有 Beans" + applicationContext.getBeansOfType(User.class));
	   // 显示地关闭 Spring 应用上下文
	   applicationContext.close();
	}
	// Java API 方式配置元信息
	public static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
	   BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);
	   beanDefinitionBuilder
	           .addPropertyValue("id", 1L)
	           .addPropertyValue("name", "小马哥");
	   // 判断如果 beanName 参数存在时
	   if (StringUtils.hasText(beanName)) {
	       // 注册 BeanDefinition
	       registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
	   } else {
	       // 非命名 Bean 注册方法
	       BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
	   }
	}
	
	public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
	   registerUserBeanDefinition(registry, null);
	}
	 // 2. 通过 @Component 方式
    @Component // 定义当前类作为 Spring Bean(组件)
    public static class Config {

        // 1. 通过 @Bean 方式定义
        /**
         * 通过 Java 注解的方式,定义了一个 Bean
         */
        @Bean(name = {"user", "xiaomage-user"})
        public User user() {
            User user = new User();
            user.setId(1L);
            user.setName("小马哥");
            return user;
        }
    }
}

7.6 Bean 的实例化方式

常规方式:
通过构造器(配置元信息:XML、Java 注解和Java API)
通过静态工厂方法(配置元信息:XML 和 Java API)在 POJO 中定义创建对象的方法
通过 Bean 工厂方法
通过FactoryBean(配置元信息:XML、Java 注解 和 Java API)

特殊方式:
通过ServiceLoaderFactoryBean(配置元信息: XML、Java注解 和 Java API)这种是Java 的SPI机制 这里直接用ServiceLoader去load配置??
通过AutowriteCapableBeanFacotry#createBean(java.lang.Class, int boolean)
通过BeanDefinitionRegistry#y#registerBeanDefinition(String, BeanDefinition)

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

   <!-- 静态方法实例化 Bean 直接调用 POJO 中的 createUser 返回一个 new 出来的 bean-->
    <bean id="user-by-static-method" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User"
          factory-method="createUser"/>

   <!-- 实例(Bean)方法实例化 Bean 通过 UserFactory 接口 提供的 createUser -->
   <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>

   <!-- FactoryBean实例化 Bean -->
   <bean id="user-by-factory-bean" class="org.geekbang.thinking.in.spring.bean.factory.UserFactoryBean" />

    <bean id="userFactory" class="org.geekbang.thinking.in.spring.bean.factory.DefaultUserFactory"/>
</beans>

FactoryBean实例化 Bean

public class UserFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return User.createUser();
    }
    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

7.7 Bean 的初始化方式

初始化的顺序也是如下:

  1. @PostConstruct 标注方法
  2. 实现InitializingBean 接口的 afterPropertiesSet方法
  3. 自定义初始化方法:
    XML配置<bean init-method=“初始化方法">
    Java 注解: @Bean(initMethod=“初始化方法”)
    Java API:AbstractBeanDefinition#setInitMethodName(String )

依赖或者初始化倒转的问题是?

public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {
    // 1. 基于 @PostConstruct 注解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化中...");
    }
    public void initUserFactory() {
        System.out.println("自定义初始化方法 initUserFactory() : UserFactory 初始化中...");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean#afterPropertiesSet() : UserFactory 初始化中...");
    }
}

@Configuration // Configuration Class
public class BeanInitializationDemo {
    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类)
        applicationContext.register(BeanInitializationDemo.class);
        // 启动 Spring 应用上下文
        applicationContext.refresh();
        // 非延迟初始化在 Spring 应用上下文启动完成后,被初始化
        System.out.println("Spring 应用上下文已启动...");
        // 依赖查找 UserFactory
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);
        System.out.println(userFactory);
        System.out.println("Spring 应用上下文准备关闭...");
        // 关闭 Spring 应用上下文
        applicationContext.close();
        System.out.println("Spring 应用上下文已关闭...");
    }

    @Bean(initMethod = "initUserFactory", destroyMethod = "doDestroy")
    @Lazy(value = false)
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

7.8 Bean 的延迟初始化

Bean延迟初始化方式Lazy Initialization

  • xml 配置:
  • Java 注解: @Lazy(true)

延迟加载和非延迟加载区别是 延迟加载在 Spring 应用上下文启动完成后,需要调用时候被初始化
而非延迟加载是 Spring 应用上下文启动之前被加载

AbstractApplicationContext#finishBeanFactroyInitialization(beanFactory) 这个逻辑是初始化非延迟加载的bean
然后进入出发beanFactory.preInstantiateSingletons() 进行初始化

7.9 销毁 Spring Bean

Bean 的销毁顺序如下:

  1. @PreDestory 标注方法
  2. 实现DisposableBean 接口的 destroy() 方法
  3. 自定义销毁方法:
    XML配置<bean destory=“销毁方法">
    Java 注解: @Bean(destroyMethod=“销毁方法”)
    Java API:AbstractBeanDefinition#setDestorytMethodName(String )

applicationContext.close()#doclose()#destroyBeans 触发 bean 的销毁方法

public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {

    // 1. 基于 @PostConstruct 注解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化中...");
    }

    public void initUserFactory() {
        System.out.println("自定义初始化方法 initUserFactory() : UserFactory 初始化中...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean#afterPropertiesSet() : UserFactory 初始化中...");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy : UserFactory 销毁中...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean#destroy() : UserFactory 销毁中...");
    }

    public void doDestroy() {
        System.out.println("自定义销毁方法 doDestroy() : UserFactory 销毁中...");
    }

    @Override
    public void finalize() throws Throwable {
        System.out.println("当前 DefaultUserFactory 对象正在被垃圾回收...");
    }
}

// 主类
@Configuration // Configuration Class
public class BeanInitializationDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类)
        applicationContext.register(BeanInitializationDemo.class);
        // 启动 Spring 应用上下文
        applicationContext.refresh();
        // 非延迟初始化在 Spring 应用上下文启动完成后,被初始化
        System.out.println("Spring 应用上下文已启动...");
        // 依赖查找 UserFactory
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);
        System.out.println(userFactory);
        System.out.println("Spring 应用上下文准备关闭...");
        // 关闭 Spring 应用上下文
        applicationContext.close();
        System.out.println("Spring 应用上下文已关闭...");
    }

    @Bean(initMethod = "initUserFactory", destroyMethod = "doDestroy")
    @Lazy(value = false)
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

7.10 回收 Spring Bean

Bean 垃圾回收 GC

  1. 关闭 Spring 容器
  2. 执行 GC
  3. Spring Bean 覆盖的 finalize() 方法被回调

7.11 Spring Bean 面试题目

  1. 如何注册一个 Spring Bean?
    通过BeanDefinition 和 外部单体bean注册实例
  2. 什么是 Spring BeanDefintion?
    定义Spring Bean 和 Spring BeanDefition
    BeanDefinition 继承了 AttributeAccessor, BeanMetadataElement
    AttributeAccessorSupport 提供通用的属性操作封装, BeanMetadataAttributeAccessor 提供Source 相关读写接口
    BeanDefition 是关于 Bean 的元信息定义的接口,存储
  3. Spring 容器是怎么样管理注册 Bean
    IoC配置元信息读取和解析、依赖查找和注入、Bean 生命周期

Spring IoC依赖查找

依赖查找的今世前生、单一类型依赖查找、集合类型依赖查找、层次性依赖查找、延迟依赖查找、安全依赖查找
内建可查找的依赖、依赖查找种的经典异常

依赖查找的今世前生

单一类型依赖查找

  • JNDI:javax.naming.Context#lookup(javax.naming.Name)
  • JavaBeans:BeanContext
    集合类型依赖查找
  • java.beans.beanContext.BeanContext
    层次

单一类型依赖查找

根据bean名称查找:getBean(String )\Spring2.5 getBean(String, Object)
根据Bean类型查找:

  • Bean实时查找 getBean(Class)
  • Spring4.1 覆盖默认参数:getBean(Class, Object)
  • Spring5.1 Bean 延迟加载
  • getBeanProvider(Class)
  • getBeanProvider(ResolvableType)
  • 根据 Bean 名称 + 类型查找:getBean(String, Class)

集合类型依赖查找

集合类型依赖查找接口——ListableBeanFactory

  • 根据Bean 类型查找
  • getBeanNamesForType(Class)
  • Spring 4.2 getBeanNamesForType(ResolvableType)
  • 获取同类型 Bean 实例列表
  • getBeansOfType(Class) 以及重载方法
  • 通过注解类型查找
  • Spring 3.0 获取标注类型 Bean 名称列表
  • getBeanNamesForAnnotation(Class<? extends Annotation>)
  • Spring 3.0 获取标注类型 Bean 实例列表
  • getBeanWithAnnotation(Class<? extends Annotation>)
  • Spring 3.0 获取指定名称 + 标注类型 Bean 实例列表

推荐使用Bean的名称判断Bean是否存在,重要的方式是判断BeanDefinition 是否存在
避免提早初始化bean,产生不确定因素。

层次性依赖查找-HierarchicalBeanFactory

  • 双亲 BeanFactory:getParentBeanFactory()
  • 层次性查找
  • 根据 Bean 名称查找:基于containsLocalBean 方法实现
  • 根据 Bean 类型查找实例列表:单一类型,BeanFactoryUtils#beanOfType;集合类型BeanFactoryUtils#beansOfTypeIncludingAncestors
  • 根据 Java 注解查找名称列表:BeanFactoryUtils#

延迟查找

ObjectFactory 和 ObjectProvider

安全依赖查找

python 小马哥 小马哥java_java_08

Spring IoC 内建可查找的依赖

python 小马哥 小马哥java_后端_09

依赖查找中的经典异常

python 小马哥 小马哥java_后端_10

面试题目

  1. ObjectFactory 与 BeanFactory 的区别?
  2. BeanFactory.getBean 操作是否线程安全?线程安全,操作过程中会增加互斥锁。