Spring学习笔记1-依赖查找、依赖注入、Bean初始化、销毁、垃圾回收GC、层次依赖查找、provider查找

依赖查找和依赖注入

依赖查找和依赖注入,是在Spring环境下获取实际对象的方式(基于IoC容器)。依赖查找偏主动,依赖注入偏被动。

依赖查找

依赖查找可以通过名称、类型和注解等三种方式实现查找。

依赖注入

依赖注入主要通过注解实现对象自动获取,不需要显示编码实现,常用语SpringBoot的框架中。此方式方便快速,理解上也相对简单。

配置Bean对象及信息

在配置对象信息时,可以通过设置Bean配置文件、配置autowire实现和@Configuration+@Bean实现。

设置Bean配置文件

可以通过设置Bean配置文件实现Bean对象及信息配置。

例如:

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">


    <bean id="user" class="springtest.ioc.overview.domain.User">
        <property name="id" value="1"/>
        <property name="name" value="xiaoming"/>
    </bean>

    <bean id="superUser" class="springtest.ioc.overview.domain.SuperUser" parent="user" primary="true">
        <property name="address" value="Hangzhou"/>
    </bean>

    <bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
        <property name="targetBeanName" value="user"/>
    </bean>

</beans>

上面代码中描述了三个Bean定义:
1、id:表示该Bean定义的编号,在后续通过依赖查找时,可依据id查找到该对象;
2、class:指定到该Bean类;
3、property:指定该Bean类对应的属性值;
4、parent:指定该类的父类对应的id;
5、primary:指定该类在同类(包含子类和父类)中被优先提取(一般基于类型的依赖查找时)。

配置autowire实现

同样,也可以通过在Bean配置文件的Bean定义时,使用autowire实现:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 通过导入复用 dependency-lookup-context.xml  -->
    <import resource="dependency-lookup-context.xml"/>

    <!-- Auto Writing -->
    <bean id="userRepository" class="springtest.ioc.overview.repository.UserRepository" autowire="byType">
        <!-- 手动配置 -->
<!--        <property name="users">-->
<!--            <util:list>-->
<!--                <ref bean="superUser"/>-->
<!--                <ref bean="user"/>-->
<!--            </util:list>-->
<!--        </property>-->

    </bean>
</beans>

上面代码中描述了Bean定义:
1、autowire:表示该Bean通过类型查找实现自动匹配;

@Configuration+@Bean实现

package springtest.ioc.overview.container;

import javafx.application.Application;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springtest.ioc.overview.domain.User;

import java.util.Map;

/**
 * 注解能力 @ApplicationContext作为 IoC 容器示例
 */
@Configuration
public class AnnotationApplicationContextAsIoCContainerDemo {
    public static void main(String[] args) {
        //创建 BeanFactory 容器
//        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //将当前类 AnnotationApplicationContextAsIoCContainerDemo作为配置类
        applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
        //启动应用上下文
        applicationContext.refresh();
        //依赖查找集合对象
        lookupByColleactionType(applicationContext);
        //关闭应用上下文
        applicationContext.close();
    }

    @Bean
    public User user(){
        User user = new User();
        user.setId(1L);
        user.setName("xiaohhong");
        return user;
    }

    private static void lookupByColleactionType(BeanFactory beanFactory) {
        if (beanFactory instanceof ListableBeanFactory) {
            ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
            Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
            System.out.println("实时(集合类型)查找:" + users);
        }
    }
}

上面代码中,通过在类前加@Configuration说明本类是一个配置类,在user()方法前加@Bean,表示该方法返回的对象User为Bean类,可用于自动注入。

然后将该类注入到IoC容器中,即将bean类加入到容器中,后续可实现依赖注入。

在方法lookupByColleactionType中,看到了通过类型查找User,使用的就是依赖注入。

应用实例

代码结构

在这里插入图片描述

依赖查找配置文件 dependency-lookup-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">


    <bean id="user" class="springtest.ioc.overview.domain.User">
        <property name="id" value="1"/>
        <property name="name" value="xiaoming"/>
    </bean>

    <bean id="superUser" class="springtest.ioc.overview.domain.SuperUser" parent="user" primary="true">
        <property name="address" value="Hangzhou"/>
    </bean>

    <bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
        <property name="targetBeanName" value="user"/>
    </bean>


</beans>

依赖查找测试代码 DependencyLookupDemo.java

package springtest.ioc.overview.dependency.lookup;


import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.annotation.Super;
import springtest.ioc.overview.domain.SuperUser;
import springtest.ioc.overview.domain.User;

import java.util.Map;

/**
 * 依赖查找示例
 * 1、通过名称查找
 * 2、通过类型查找
 */
public class DependencyLookupDemo {

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

    public static void lookupInRealTime(BeanFactory beanFactory) {
        User user = (User) beanFactory.getBean("user");
        System.out.println("实时查找:" + user);
    }

    private static void lookInLazy(BeanFactory beanFactory) {
        ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
        User user = objectFactory.getObject();
        System.out.println("延迟查找:" + user);
    }

    private static void lookupByType(BeanFactory beanFactory) {
        User user = beanFactory.getBean(User.class);
        System.out.println("实时(类型)查找:" + user);
    }

    private static void lookupByColleactionType(BeanFactory beanFactory) {
        if (beanFactory instanceof ListableBeanFactory) {
            ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
            Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
            System.out.println("实时(集合类型)查找:" + users);
        }
    }

    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的用户集合:" + users);
        }
    }
}

依赖注入配置文件 dependency-injection-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 通过导入复用 dependency-lookup-context.xml  -->
    <import resource="dependency-lookup-context.xml"/>

    <!-- Auto Writing -->
    <bean id="userRepository" class="springtest.ioc.overview.repository.UserRepository" autowire="byType">
        <!-- 手动配置 -->
<!--        <property name="users">-->
<!--            <util:list>-->
<!--                <ref bean="superUser"/>-->
<!--                <ref bean="user"/>-->
<!--            </util:list>-->
<!--        </property>-->

    </bean>
</beans>

依赖注入测试代码 DependencyInjectionDemo.java

package springtest.ioc.overview.dependency.injection;


import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.Environment;
import springtest.ioc.overview.annotation.Super;
import springtest.ioc.overview.domain.User;
import springtest.ioc.overview.repository.UserRepository;

import java.util.Map;

/**
 * 依赖注入示例
 * 1、通过名称查找
 * 2、通过类型查找
 */
public class DependencyInjectionDemo {

    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 = beanFactory.getBean("userRepository", UserRepository.class);
        System.out.println(userRepository.getUsers());

        //依赖来源二:依赖注入(内建依赖)
        System.out.println(userRepository.getBeanFactory());
//        System.out.println(userRepository.getBeanFactory() == beanFactory);

        ObjectFactory objectFactory = userRepository.getObjectFactory();
        System.out.println(objectFactory.getObject());

        //依赖查找
//        System.out.println(beanFactory.getBean(BeanFactory.class));

        //依赖来源三:容器内建 Bean
        Environment environment = beanFactory.getBean(Environment.class);
        System.out.println("获取 environment 类型的 Bean:" + environment);


        whoIsIoCContainer(userRepository, applicationContext);
    }


    private static void whoIsIoCContainer(UserRepository userRepository, ApplicationContext applicationContext) {


        // ConfigurableApplicationContext <- ApplicationContext <- BeanFactory

        // ConfigurableApplicationContext#getBeanFactory()


        // 这个表达式为什么不会成立
        System.out.println(userRepository.getBeanFactory() == applicationContext);

        // ApplicationContext is BeanFactory

    }


}

其他代码

Super 注解类

package springtest.ioc.overview.annotation;


import java.lang.annotation.*;

/**
 * 超级
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Super {
}

User类

package springtest.ioc.overview.domain;

/**
 * 用户类
 */
public class User {

    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

SuperUser类

package springtest.ioc.overview.domain;

import springtest.ioc.overview.annotation.Super;

@Super
public class SuperUser extends User{
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "SuperUser{" +
                "address='" + address + '\'' +
                "} " + super.toString();
    }
}

UserRepository

package springtest.ioc.overview.repository;

import javafx.application.Application;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import springtest.ioc.overview.domain.User;

import java.util.Collection;

/**
 * 用户的信息仓库
 */
public class UserRepository {

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

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

    private ObjectFactory<User> 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<User> getObjectFactory() {
        return objectFactory;
    }

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

BeanFactoryAsIoCContainerDemo

package springtest.ioc.overview.container;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import springtest.ioc.overview.domain.User;

import java.util.Map;

/**
 * 作为 IoC 容器示例
 */
public class BeanFactoryAsIoCContainerDemo {
    public static void main(String[] args) {
        //创建 BeanFactory 容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //加载配置
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        //Xml 配置文件 ClassPath 路径
        String location = "classpath:/META-INF/dependency-lookup-context.xml";
        System.out.println("number beans:" + reader.loadBeanDefinitions(location));

        //依赖查找集合对象
        lookupByColleactionType(beanFactory);
    }

    private static void lookupByColleactionType(BeanFactory beanFactory) {
        if (beanFactory instanceof ListableBeanFactory) {
            ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
            Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
            System.out.println("实时(集合类型)查找:" + users);
        }
    }
}

运行结构

在这里插入图片描述

AnnotationApplicationContextAsIoCContainerDemo

package springtest.ioc.overview.container;

import javafx.application.Application;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springtest.ioc.overview.domain.User;

import java.util.Map;

/**
 * 注解能力 @ApplicationContext作为 IoC 容器示例
 */
@Configuration
public class AnnotationApplicationContextAsIoCContainerDemo {
    public static void main(String[] args) {
        //创建 BeanFactory 容器
//        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //将当前类 AnnotationApplicationContextAsIoCContainerDemo作为配置类
        applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
        //启动应用上下文
        applicationContext.refresh();
        //依赖查找集合对象
        lookupByColleactionType(applicationContext);
        //关闭应用上下文
        applicationContext.close();
    }

    @Bean
    public User user(){
        User user = new User();
        user.setId(1L);
        user.setName("xiaohhong");
        return user;
    }

    private static void lookupByColleactionType(BeanFactory beanFactory) {
        if (beanFactory instanceof ListableBeanFactory) {
            ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
            Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
            System.out.println("实时(集合类型)查找:" + users);
        }
    }
}

运行结果

在这里插入图片描述

应用实例2

应用实例2引入别名 alias 和 BeanDefinition 相关操作。

代码结构图

在这里插入图片描述

架构配置 bean-definition-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 导入第三方 Spring xml 配置文件 -->
    <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
    <!-- 将 Spring 中的 "user" Bean 关联/建立 别名 "szc-user"-->
    <alias name="user" alias="szc-user"/>

</beans>

上述代码通过 + resource方式引入了应用实例1的项目配置,同时同归 + name + alias方式为user增加了别名。

验证别名的作用

package springtest.bean.definition;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.domain.User;

/**
 * Bean 的别名示例
 */
public class BeanAliasDemo {
    public static void main(String[] args) {
        //配置 xml 配置文件
        //启动 Spring 应用上下文
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definition-context.xml");
        //通过别名 "szc-user" 获取 User 的 Bean
        User userAlias = (User)beanFactory.getBean("szc-user");
        User userOrigin = (User)beanFactory.getBean("user");
        System.out.println("userAlias == userOrigin ? :" + (userAlias == userOrigin));
    }
}

上述代码通过名称获取了user的bean对象,一个用的时真名,一个用的时别名。

BeanDefinition 使用(通过代码定义和创建bean)

package springtest.bean.definition;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import springtest.ioc.overview.domain.User;

/**
 * BeanDefinition 构建示例
 */
public class BeanDefinitionCreationDemo {
    public static void main(String[] args) {
        //1. 通过 BeanDefinitionBuilder 构建 Bean 类型(配置文件都不用写)
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        //通过水泥杆设置
        beanDefinitionBuilder.addPropertyValue("id", 34);
        beanDefinitionBuilder.addPropertyValue("name", "nihaoa");
        //获取 BeanDefinition 实例
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        //BeanDefinition 并非 Bean 的最终状态
        System.out.println(beanDefinition.getBeanClassName());

        //2. 通过 AbstractBeanDefinition 以及派生类构建 Bean 类型(配置文件都不用写)
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        //设置 Bean 的类型
        genericBeanDefinition.setBeanClass(User.class);
        //通过 MultablePropertyValues 批量操作属性
        MutablePropertyValues propertyValues = new MutablePropertyValues();
//        propertyValues.addPropertyValue("id", 43);
//        propertyValues.addPropertyValue("name", "nihaoa2");
        propertyValues.add("id", 55);
        propertyValues.add("name", "nihaoa3");
        //通过 set MultablePropertyValues 批量操作属性
        genericBeanDefinition.setPropertyValues(propertyValues);
    }
}

上述代码分别通过BeanDefinition和AbstractBeanDefinition定义bean对象,没有使用项目配置文件定位,是一种创建bean的新方案。

通过 AnnotationConfigApplicationContext 创建bean

package springtest.bean.definition;

import javafx.beans.binding.ObjectExpression;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import springtest.ioc.overview.domain.User;

import java.util.Map;

/**
 * 注解 BeanDefinition 示例
 */
@Import(AnnotationBeanDefinitionDemo.Config.class)//3.通过 @Import 方式导入
public class AnnotationBeanDefinitionDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类)
        applicationContext.register(Config.class);
        //启动应用上下文
        applicationContext.refresh();

        //通过 BeanDefinition 注册 API 实现
        //1.命名 bean 的注册方式
        registerBeanDefinition(applicationContext, "szc-2-user");
        //2.非命名 bean 的注册方式
        registerBeanDefinition(applicationContext, "");

        //1.通过 @Bean 方式进行定义
        //2.通过 @Component 方式进行定义
        //3.通过 @Import 方式导入

        Map<String, Config> configBeans = applicationContext.getBeansOfType(Config.class);
        System.out.println("Config 类型的所有 Beans:" + applicationContext.getBeansOfType(Config.class));
        System.out.println("User 类型的所有 Beans:" + applicationContext.getBeansOfType(User.class));

        //关闭应用上下文
        applicationContext.close();
    }

    /**
     * 命名 Bean 的注册方式
     *
     * @param registry
     * @param beanName
     */
    public static void registerBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("id", 2L);
        beanDefinitionBuilder.addPropertyValue("name", "xiaoming");

        //判断如果 beanName 参数存在时
        if (StringUtils.hasText(beanName)) {
            //注册 BeanDefinition
            registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
        } else {
            //非命名 bean 的注册方式
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
        }


    }

    @Component //定义当前类作为 Spring Bean 组件//2.通过 @Component 方式进行定义
    public static class Config {

        @Bean(name = {"user", "szc-user"})//1.通过 @Bean 方式进行定义
        public User user() {
            User user = new User();
            user.setId(1L);
            user.setName("xiaohhong");
            return user;
        }
    }
}

上述代码通过注解@Import导入配置类,并在配置类上使用@Bean注解,然后通过查类型的方式获取bean对象。

运行结果

在这里插入图片描述

应用实例3

应用实例3衔接应用实例2。
实例应用3实现静态方法\调用实例Bean静态方法和通过FactoryBean获得Bean对象。

代码结构图

在这里插入图片描述

User类

相对一应用实例2的User类,增加了public静态方法createUser:

package springtest.ioc.overview.domain;

/**
 * 用户类
 */
public class User {

    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    /**
     * 静态方法构建 bean
     * @return
     */
    public static User createUser(){
        User user = new User();
        user.setId(1L);
        user.setName("xiaohhong");
        return user;
    }
}

用户工厂接口 UserFactory

接口包含默认方法createUser:

package springtest.bean.definition.factory;

import springtest.ioc.overview.domain.User;

public interface UserFactory {

    default User createUser(){
        return User.createUser();
    }
}

UserFactory接口实现类 DefaultUserFactory

使用接口默认实现:

package springtest.bean.definition.factory;

import springtest.ioc.overview.domain.User;

public class DefaultUserFactory implements UserFactory {
}

创建 UserFactoryBean类,实现FactoryBean接口

package springtest.bean.definition.factory;

import org.springframework.beans.factory.FactoryBean;
import springtest.ioc.overview.domain.User;

/**
 * FactoryBean 的实现
 */
public class UserFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return User.createUser();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

配置文件 bean-instantiation-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 静态方法实例化 Bean -->
   <bean id="user-by-static-method" class="springtest.ioc.overview.domain.User"
         factory-method="createUser"/>

    <!-- 实例 (Bean) 方法实例化 Bean -->
    <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>

    <bean id="userFactory" class="springtest.bean.definition.factory.DefaultUserFactory"/>

<!-- FactoryBean 实例化 Bean-->
    <bean id="user-by-factory-bean" class="springtest.bean.definition.factory.UserFactoryBean"/>

</beans>

包含静态方法实例化Bean、实例方法实例化Bean和FactoryBean方法。
factory-method指向类中的静态方法,factory-bean指向实例Bean。

调试类 BeanInstantiationDemo

package springtest.bean.definition;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.domain.User;

/**
 * Bean 实例化
 */
public class BeanInstantiationDemo {

    public static void main(String[] args) {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-instantiation-context.xml");
        User user = beanFactory.getBean("user-by-static-method", User .class);
        User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User .class);
        User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User .class);
        System.out.println(user);
        System.out.println(userByInstanceMethod);
        System.out.println(user == userByInstanceMethod);

        System.out.println(user == userByFactoryBean);
        System.out.println(user == userByInstanceMethod);
    }
}

运行结果

在这里插入图片描述

应用实例4

应用实例4衔接应用实例3,主要讲解ServiceLoader加载Bean。

代码结构图

在这里插入图片描述

创建 springtest.bean.definition.factory.UserFactory

在resource下创建service路径,然后创建springtest.bean.definition.factory.UserFactory。该文件名指向将使用的生成User的接口,其内容是接口实现类的路径:

springtest.bean.definition.factory.DefaultUserFactory

创建配置文件 special-bean-instantiation-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- ServiceLoader实例化 Bean -->
    <bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
        <property name="serviceType" value="springtest.bean.definition.factory.UserFactory"/>
    </bean>

</beans>

该配置文件主要定义了ServiceFactoryBean类,并将其serviceType指向UserFactory接口(之后该接口通过前面讲解的service目录下的文件,找到对应的接口实现类)。

测试类SpecialBeanInstantiationDemo

package springtest.bean.definition;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;
import springtest.ioc.overview.domain.User;

import java.util.Iterator;
import java.util.ServiceLoader;

import static java.util.ServiceLoader.load;

/**
 * Bean 实例化
 */
public class SpecialBeanInstantiationDemo {

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

        //通过 AppliccationContext 获取 AutowireCapableBeanFactory
        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();

        ServiceLoader<UserFactory> serviceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);

        displayServiceLoader(serviceLoader);

        demoServiceLoader();

        //创建 UserFactory 对象,通过 AutowireCapableBeanFactory
        UserFactory userFactory = beanFactory.createBean(DefaultUserFactory.class);
        System.out.println(userFactory.createUser());

    }

    public static void demoServiceLoader() {
        ServiceLoader<UserFactory> serviceLoader = load(UserFactory.class, Thread.currentThread().getContextClassLoader());
        displayServiceLoader(serviceLoader);
    }

    public static void displayServiceLoader(ServiceLoader<UserFactory> serviceLoader){
        Iterator<UserFactory> iterator = serviceLoader.iterator();
        while (iterator.hasNext()) {
            UserFactory userFactory = iterator.next();
            System.out.println(userFactory.createUser());
        }
    }
}

运行结果

在这里插入图片描述

应用实例5

应用实例5衔接应用实例4,主要讲解Bean的三种初始化方法:
1、@PostConstruct;
2、InitializingBean的afterPropertiesSet();
3、@Bean(initMethod="…")。

代码架构

在这里插入图片描述

DefaultUserFactory 修改

package springtest.bean.definition.factory;

import org.springframework.beans.factory.InitializingBean;
import springtest.ioc.overview.domain.User;

import javax.annotation.PostConstruct;

public class DefaultUserFactory implements UserFactory, InitializingBean {

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

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

    //3.基于 InitializingBean:afterPropertiesSet()
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean:afterPropertiesSet() UserFactory 初始化中...(优先级2)");
    }
}

BeanInitializationDemo

package springtest.bean.definition;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;

@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 Configuration class (配置类)
        applicationContext.register(BeanInitializationDemo.class);
        //启动 Spring 上下文
        applicationContext.refresh();

        // 依赖查找 UserFactory
//        UserFactory userFactory = (UserFactory)applicationContext.getBean("userFactory");
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);

        //关闭 Spring 上下文
        applicationContext.close();
    }

    //2.基于 initMethod 指定初始化方法
    @Bean(initMethod = "initUserFactory")
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

运行结果

在这里插入图片描述

应用实例6

应用实例6衔接应用实例5,主要讲解Bean的延迟初始化方法:
通过在@Bean类前加上@Lazy注释;如果写成@Lazy(value = false),表示为非延迟初始化。

BeanInitializationDemo

package springtest.bean.definition;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;

@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 Configuration class (配置类)
        applicationContext.register(BeanInitializationDemo.class);
        //启动 Spring 上下文
        applicationContext.refresh();

        // 依赖查找 UserFactory
//        UserFactory userFactory = (UserFactory)applicationContext.getBean("userFactory");
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);

        //关闭 Spring 上下文
        applicationContext.close();
    }

    //2.基于 initMethod 指定初始化方法
    @Bean(initMethod = "initUserFactory")
    @Lazy//(value = false)
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

运行结果

1、@Lazy:延迟初始化
在这里插入图片描述

2、@Lazy(value = false):非延迟初始化

在这里插入图片描述

应用实例7

应用实例7衔接应用实例6,主要讲解Bean的销毁方法:
1、@PreDestroy;
2、DestroyBean的destroy();
3、@Bean(destroyMethod="…")。

DefaultUserFactory

package springtest.bean.definition.factory;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import springtest.ioc.overview.domain.User;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class DefaultUserFactory implements UserFactory, InitializingBean , DisposableBean {

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

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

    //3.基于 InitializingBean:afterPropertiesSet()
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean:afterPropertiesSet() UserFactory 初始化中...(优先级2)");
    }

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

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

    public void doDestroy(){
        System.out.println("自定义初始化方法#doDestroy() : UserFactory 销毁中 ...(优先级3)");
    }
}

BeanInitializationDemo

package springtest.bean.definition;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;

@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 Configuration class (配置类)
        applicationContext.register(BeanInitializationDemo.class);
        //启动 Spring 上下文
        applicationContext.refresh();

        //非延迟初始化在 Spring 应用上下文启动完成后,被初始化
        System.out.println("Spring 应用上下文启动完成...");

        // 依赖查找 UserFactory
//        UserFactory userFactory = (UserFactory)applicationContext.getBean("userFactory");
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);

        System.out.println(userFactory);

        System.out.println("Spring 应用上下文准备关闭...");

        //关闭 Spring 上下文
        applicationContext.close();

        System.out.println("Spring 应用上下文关闭完成...");
    }

    //2.基于 initMethod 指定初始化方法
    @Bean(initMethod = "initUserFactory", destroyMethod = "doDestroy")
    @Lazy(value = false)
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

运行结果

在这里插入图片描述

应用实例8

应用实例8衔接应用实例7,主要讲解Spring垃圾回收GC:
1、通过上下文close()时,调用finialize()方法实现:

代码架构

在这里插入图片描述

DefaultUserFactory

package springtest.bean.definition.factory;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import springtest.ioc.overview.domain.User;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {

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

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

    //3.基于 InitializingBean:afterPropertiesSet()
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean:afterPropertiesSet() UserFactory 初始化中...(优先级2)");
    }

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

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

    public void doDestroy() {
        System.out.println("自定义初始化方法#doDestroy() : UserFactory 销毁中 ...(优先级3)");
    }

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

BeanGarbageColleationDemo

package springtest.bean.definition;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import springtest.bean.definition.factory.UserFactory;

/**
 * Bean 垃圾回收(GC) 示例
 */
public class BeanGarbageColleationDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 Configuration class (配置类)
        applicationContext.register(BeanInitializationDemo.class);
        //启动 Spring 上下文
        applicationContext.refresh();

        //关闭 Spring 上下文
        applicationContext.close();

        System.out.println("Spring 应用上下文关闭完成...");

        //强制出发 GC
        System.gc();
    }
}

运行结果

在这里插入图片描述

应用实例9

应用实例9衔接应用实例8,单体 Bean 注册实例:
1、注册外部单例对象,.registerSingleton(…):

代码架构

在这里插入图片描述

SingletonBeanRegistrationDemo

package springtest.bean.definition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;

/**
 * 单体 Bean 注册实例
 */
public class SingletonBeanRegistrationDemo {
    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 创建外部单例对象
        UserFactory userFactory = new DefaultUserFactory();
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();

        // 注册外部单例对象
        beanFactory.registerSingleton("userFactory", userFactory);

        //启动 Spring 上下文
        applicationContext.refresh();

        //通过依赖查找的方式来获取 UserFactory
        UserFactory userFactoryByLookup = beanFactory.getBean("userFactory", UserFactory.class);

        System.out.println("userFactory == userFactoryByLookup:" + (userFactory == userFactoryByLookup));

        //关闭 Spring 上下文
        applicationContext.close();
    }
}

运行结果

在这里插入图片描述

应用实例10

应用实例10,单一类型依赖查找实例:
1、涉及到ObjectProvider:

代码架构

在这里插入图片描述

ObjectProviderDemo

package springtest.dependency.lookup;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

/**
 * 通过 PbjectProvider 进行依赖查找
 */
public class ObjectProviderDemo { // @Configuration 是非必须注解
    public static void main(String[] args) {
        //创建 BeanFactory 容器
//        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //将当前类 ObjectProviderDemo 作为配置类
        applicationContext.register(ObjectProviderDemo.class);
        //启动应用上下文
        applicationContext.refresh();
        //依赖查找集合对象
        lookupByObjectProvider(applicationContext);
        //关闭应用上下文
        applicationContext.close();
    }

    @Bean
    public String helloworld(){ // 方法名就是 Bean 名称 = "helloworld"
        return "Hello, World!";
    }

    private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
        System.out.println(objectProvider.getObject());
    }
}

1、在使用ObjectProvider时,可以不需要再类前注明@Configuration注释;
2、加上@Bean注释后,方法名就变成了Bean名称;
3、上下文对象通过getBeanProvider获得ObjectProvider对象,然后ObjectProvider对象通过getObject方法获得对象。

运行结果

在这里插入图片描述

应用实例11

应用实例11,主讲层次依赖查找:
1、涉及到ConfigurableListableBeanFactory类的getParentBeanFactory()方法和HierarchicalBeanFactory类的setParentBeanFactory()方法,用来实现对父类的提取和设置。

代码架构

在这里插入图片描述

HierarchicalDependencyLookupDemo

package springtest.dependency.lookup;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 层次性依赖查找示例
 */
public class HierarchicalDependencyLookupDemo {

    public static void main(String[] args) {
        //创建 BeanFactory 容器
//        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //将当前类 ObjectProviderDemo 作为配置类
        applicationContext.register(HierarchicalDependencyLookupDemo.class);

        //1. 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListableBeanFactory
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        System.out.println("当前 BeanFactory 的 Parent BeanFactory:" + beanFactory.getParentBeanFactory());

        //2. 设置 Parent BeanFactory
        HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
        beanFactory.setParentBeanFactory(createParentBeanFactory());
        System.out.println("当前 BeanFactory 的 Parent BeanFactory:" + beanFactory.getParentBeanFactory());

        displayContainsLocalBean(beanFactory, "user");
        displayContainsLocalBean(parentBeanFactory, "user");

        displayContainsBean(beanFactory, "user");
        displayContainsBean(parentBeanFactory, "user");
        //启动应用上下文
        applicationContext.refresh();

        //关闭应用上下文
        applicationContext.close();
    }

    private static void displayContainsBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.printf("当前 BeanFactory[name: %s] 是否包含 bean[name: %s]: %s\n", beanFactory, beanName,
                containsBean(beanFactory, beanName));
    }

    private static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName){
        BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
        if (parentBeanFactory instanceof HierarchicalBeanFactory) {
            HierarchicalBeanFactory parentHierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
            if(containsBean(parentHierarchicalBeanFactory, beanName)){
                return true;
            }
        }
        return beanFactory.containsLocalBean(beanName);
    }

    private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.printf("当前 BeanFactory[name: %s] 是否包含 local bean[name: %s]: %s\n", beanFactory, beanName,
                beanFactory.containsLocalBean(beanName));
    }

    private static ConfigurableListableBeanFactory createParentBeanFactory() {
        //创建 BeanFactory 容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //加载配置
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        //Xml 配置文件 ClassPath 路径
        String location = "classpath:/META-INF/dependency-lookup-context.xml";

        reader.loadBeanDefinitions(location);
        return beanFactory;
    }
}

1、通过ConfigurableListableBeanFactory类的getParentBeanFactory()方法提取父类;
2、通过HierarchicalBeanFactory类的setParentBeanFactory()方法设置父类。

运行结果

/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=50804:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/tools.jar:/Users/susie/_my_java/Spring/geekbang-lessons-master/springtest/dependency-lookup/target/classes:/Users/susie/.m2/repository/org/springframework/spring-context/5.2.2.RELEASE/spring-context-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-aop/5.2.2.RELEASE/spring-aop-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-beans/5.2.2.RELEASE/spring-beans-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-core/5.2.2.RELEASE/spring-core-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-jcl/5.2.2.RELEASE/spring-jcl-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-expression/5.2.2.RELEASE/spring-expression-5.2.2.RELEASE.jar:/Users/susie/_my_java/Spring/geekbang-lessons-master/springtest/ioc-container-overview/target/classes:/Users/susie/.m2/repository/org/springframework/spring-jdbc/5.2.2.RELEASE/spring-jdbc-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-tx/5.2.2.RELEASE/spring-tx-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-webflux/5.2.2.RELEASE/spring-webflux-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-web/5.2.2.RELEASE/spring-web-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/io/projectreactor/reactor-core/3.3.1.RELEASE/reactor-core-3.3.1.RELEASE.jar:/Users/susie/.m2/repository/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar:/Users/susie/.m2/repository/org/springframework/spring-webmvc/5.2.2.RELEASE/spring-webmvc-5.2.2.RELEASE.jar springtest.dependency.lookup.HierarchicalDependencyLookupDemo
当前 BeanFactory 的 Parent BeanFactory:null
当前 BeanFactory 的 Parent BeanFactory:org.springframework.beans.factory.support.DefaultListableBeanFactory@2a2d45ba: defining beans [user,superUser,objectFactory]; root of factory hierarchy
当前 BeanFactory[name: org.springframework.beans.factory.support.DefaultListableBeanFactory@4678c730: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,hierarchicalDependencyLookupDemo]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@2a2d45ba] 是否包含 local bean[name: user]: false
当前 BeanFactory[name: org.springframework.beans.factory.support.DefaultListableBeanFactory@6767c1fc: defining beans [user,superUser,objectFactory]; root of factory hierarchy] 是否包含 local bean[name: user]: true
当前 BeanFactory[name: org.springframework.beans.factory.support.DefaultListableBeanFactory@4678c730: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,hierarchicalDependencyLookupDemo]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@2a2d45ba] 是否包含 bean[name: user]: true
当前 BeanFactory[name: org.springframework.beans.factory.support.DefaultListableBeanFactory@6767c1fc: defining beans [user,superUser,objectFactory]; root of factory hierarchy] 是否包含 bean[name: user]: true

Process finished with exit code 0

应用实例12

应用实例12,主讲通过ObjectProvider进行Bean查找:
1、通过调用applicationContext.getBeanProvider(类型类名)方法获得带类型参数的ObjectProvider对象;
2、ObjectProvider对象通过方法getObject())获得对象;
3、ObjectProvider对象通过方法getIfAvailable(lambda表达式,返回的是Bean对象)获得对象(lambda返回的表达式);
4、ObjectProvider对象通过迭代器,循环获得对象;
5、ObjectProvider对象通过调用stream()方法,循环获得对象;

代码架构

在这里插入图片描述

ObjectProviderDemo

package springtest.dependency.lookup;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import springtest.ioc.overview.domain.User;

/**
 * 通过 PbjectProvider 进行依赖查找
 */
public class ObjectProviderDemo { // @Configuration 是非必须注解
    public static void main(String[] args) {
        //创建 BeanFactory 容器
//        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //将当前类 ObjectProviderDemo 作为配置类
        applicationContext.register(ObjectProviderDemo.class);
        //启动应用上下文
        applicationContext.refresh();

        //依赖查找集合对象
        lookupByObjectProvider(applicationContext);
        lookupIfAvailable(applicationContext);
        lookupByStreamOps(applicationContext);

        //关闭应用上下文
        applicationContext.close();
    }

    private static void lookupByStreamOps(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
        // 1.通过迭代实现
        Iterable<String> stringIterable = objectProvider;
        for(String string : stringIterable){
            System.out.println(string);
        }

        // 2.通过 Stream 实现
        objectProvider.stream().forEach(System.out::println);
    }

    private static void lookupIfAvailable(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
        User user = userObjectProvider.getIfAvailable(() -> User.createUser());
        System.out.println("当前 User 对象:" + user);
    }

    private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
        System.out.println(objectProvider.getObject());
    }

    @Bean
    @Primary
    public String helloworld() { // 方法名就是 Bean 名称 = "helloworld"
        return "Hello, World!";
    }

    @Bean
    public String message() { // 方法名就是 Bean 名称 = "helloworld"
        return "message";
    }
}

运行结果

在这里插入图片描述

应用实例13

应用实例13,主讲线程安全操作
1、 BeanFactory#getBean 方法线程不安全,无对象将报错;
2、ObjectFactory#getObject 方法线程不安全,无对象将报错;
3、ObjectProvider#getIfAvailable 方法线程安全,无对象不报错;
4、ListableBeanFactory#getBeanOfType 方法线程安全,无对象不报错;
5、ObjectProvider#Stream 方法线程安全,无对象不报错。

代码架构

在这里插入图片描述

TypeSfaetyDependencyLookupDemo

package springtest.dependency.lookup;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.w3c.dom.ls.LSOutput;
import springtest.ioc.overview.domain.User;

/**
 * 线程安全操作示例
 */
public class TypeSfaetyDependencyLookupDemo {
    public static void main(String[] args) {
        //创建 BeanFactory 容器
//        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //将当前类 ObjectProviderDemo 作为配置类
        applicationContext.register(TypeSfaetyDependencyLookupDemo.class);
        //启动应用上下文
        applicationContext.refresh();

        // 演示 BeanFactory#getBean 方法的线程安全性(线程不安全,无对象将报错)
        displayBeanFactoryGetBean(applicationContext);

        // 演示 ObjectFactory#getObject 方法的线程安全性(线程不安全,无对象将报错)
        displayObjectFactoryGetObject(applicationContext);

        // 演示 ObjectProvider#getIfAvailable 方法的线程安全性(线程安全,无对象不报错)
        displayObjectProviderGetIfAvailable(applicationContext);


        // 演示 ListableBeanFactory#getBeanOfType 方法的线程安全性(线程安全,无对象不报错)
        displayListableBeanFactoryGetBeanOfType(applicationContext);

        // 演示 ObjectProvider#Stream 方法的线程安全性(线程安全,无对象不报错)
        displayObjectProviderStream(applicationContext);

        //关闭应用上下文
        applicationContext.close();
    }

    private static void displayObjectProviderStream(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
        printBeansExecption("displayObjectProviderStream", () -> userObjectProvider.forEach(System.out::println));
    }

    private static void displayListableBeanFactoryGetBeanOfType(ListableBeanFactory beanFactory) {
        printBeansExecption("displayListableBeanFactoryGetBeanOfType", () -> beanFactory.getBeansOfType(User.class));
    }

    private static void displayObjectProviderGetIfAvailable(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
        printBeansExecption("displayObjectProviderGetIfAvailable", () -> userObjectProvider.getIfAvailable());
    }


    private static void displayObjectFactoryGetObject(AnnotationConfigApplicationContext applicationContext) {
        ObjectFactory<User> userObjectFactory = applicationContext.getBeanProvider(User.class);
        printBeansExecption("displayObjectFactoryGetObject", () -> userObjectFactory.getObject());
    }

    private static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
        printBeansExecption("displayBeanFactoryGetBean", () -> beanFactory.getBean(User.class));
    }

    private static void printBeansExecption(String source, Runnable runnable) {
        System.out.println("====================================");
        System.out.println("Source from : " + source);
        try {
            runnable.run();
        } catch (BeansException exception) {
            exception.printStackTrace();
        }
    }
}

运行结果

在这里插入图片描述

应用实例14

应用实例14,主讲bean获取时可能会遇到的异常:
1、Bean对象不唯一;
2、Bean对象定义失败;
3、Bean对象创建失败;

代码架构

在这里插入图片描述

NoUniqueBeanDefinitionExceptionDemo.java 类定义不唯一

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package springtest.dependency.lookup;

import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

/**
 * {@link NoUniqueBeanDefinitionException} 示例代码
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class NoUniqueBeanDefinitionExceptionDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 将当前类 NoUniqueBeanDefinitionExceptionDemo 作为配置类(Configuration Class)
        applicationContext.register(NoUniqueBeanDefinitionExceptionDemo.class);
        // 启动应用上下文
        applicationContext.refresh();

        try {
            // 由于 Spring 应用上下文存在两个 String 类型的 Bean,通过单一类型查找会抛出异常
            applicationContext.getBean(String.class);
        } catch (NoUniqueBeanDefinitionException e) {
            System.err.printf(" Spring 应用上下文存在%d个 %s 类型的 Bean,具体原因:%s%n",
                    e.getNumberOfBeansFound(),
                    String.class.getName(),
                    e.getMessage());
        }

        // 关闭应用上下文
        applicationContext.close();
    }

    @Bean
    public String bean1() {
        return "1";
    }

    @Bean
    public String bean2() {
        return "2";
    }

    @Bean
    public String bean3() {
        return "3";
    }
}

运行结果:
在这里插入图片描述

BeanInstantiationExceptionDemo 类实例化异常

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package springtest.dependency.lookup;

import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * {@link BeanInstantiationException} 实例
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class BeanInstantiationExceptionDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 BeanDefinition Bean Class 是一个 CharSequence 接口
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CharSequence.class);
        applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());

        // 启动应用上下文
        applicationContext.refresh();

        // 关闭应用上下文
        applicationContext.close();
    }

}

运行结果:
在这里插入图片描述

BeanCreationExceptionDemo 类创建异常

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package springtest.dependency.lookup;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.annotation.PostConstruct;

/**
 * {@link BeanCreationException} 示例
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class BeanCreationExceptionDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册 BeanDefinition Bean Class 是一个 POJO 普通类,不过初始化方法回调时抛出异常
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(POJO.class);
        applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());

        // 启动应用上下文
        applicationContext.refresh();

        // 关闭应用上下文
        applicationContext.close();
    }

    static class POJO implements InitializingBean {

        @PostConstruct // CommonAnnotationBeanPostProcessor
        public void init() throws Throwable {
            throw new Throwable("init() : For purposes...");
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            throw new Exception("afterPropertiesSet() : For purposes...");
        }
    }
}

运行结果:
1)只看afterPropertiesSet
在这里插入图片描述

2)只看PostConstruct
在这里插入图片描述

应用实例15

应用实例15,主讲获取bean对象的3种手动setter方法和2种自动方法:
1、XML-ref方法;
2、构造函数(@Bean);
3、api方法;
4、XML-Autowire方法。

代码架构

在这里插入图片描述

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springtest</artifactId>
        <groupId>springtest</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dependency-injection</artifactId>

    <dependencies>
        <!-- Spring IoC 核心模块 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <!-- 复用 ioc-container-overview</artifactId> -->
        <dependency>
            <groupId>${groupId}</groupId>
            <artifactId>ioc-container-overview</artifactId>
            <version>${version}</version>
        </dependency>
    </dependencies>


</project>

UserHolder.java

package spring.ioc.dependency.injection;

import springtest.ioc.overview.domain.User;

/**
 * User 的 Holder 类
 */
public class UserHolder {
    private User user;

    public UserHolder() {
    }

    public UserHolder(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "UserHolder{" +
                "user=" + user +
                '}';
    }
}

通过该类实现bean类演示

XML-ref 实现bean配置

xml配置文件dependency-setter-injection.xml :

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>

    <bean class="spring.ioc.dependency.injection.UserHolder">
        <property name="user" ref="superUser"/>
    </bean>

</beans>

1、通过import引用之前的xml配置文件内容;
2、定义bean UserHolder,并在属性配置中,使用“ref”实现类的注入(引用);

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

/**
 * 基于 XML 资源的依赖 setter 方法注入
 */
public class XmlDependencySetterInjectionDemo {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        String xmlResourcePath = "classpath:/META-INF/dependency-setter-injection.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
        //依赖查找并且创建 Bean
        UserHolder userHolder = beanFactory.getBean(UserHolder.class);

        System.out.println(userHolder);
    }
}

通过getBean获取UserHolder的bean对象。在获取时通过setter方法将superUser对象赋值给user成员变量。

运行结果

在这里插入图片描述

构造函数(@Bean) 实现bean配置

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;

/**
 * 基于 XML 资源的依赖 setter 方法注入
 */
public class AnnotationDependencySetterInjectionDemo {

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类)
        applicationContext.register(AnnotationDependencySetterInjectionDemo.class);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();


        //依赖查找并且创建 Bean
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);

        System.out.println(userHolder);

        //关闭应用上下文
        applicationContext.close();
    }

    @Bean
    public UserHolder userHolder(User user){
        UserHolder userHolder = new UserHolder();
        userHolder.setUser(user);
        return userHolder;
//        return new UserHolder(user);
    }
}

通过@Bean注解定义bean,并通过构造函数或setter获得对象。

运行结果

在这里插入图片描述

api方法 实现bean配置

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;

/**
 * 基于 API 注解的依赖 setter 方法注入
 */
public class ApiDependencySetterInjectionDemo {

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 UserHolder 的 BeanDefinition
        BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
        //生成 UserHolder 的 BeanDefinition
        applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找并且创建 Bean
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);

        System.out.println(userHolder);

        //关闭应用上下文
        applicationContext.close();
    }

    /**
     * 为 {@Link UserHolder} 生成 {@Link BeanDefinition}
     * @return
     */
    private static BeanDefinition createUserHolderBeanDefinition() {
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        definitionBuilder.addPropertyReference("user", "superUser");
        return definitionBuilder.getBeanDefinition();
    }

//    @Bean
//    public UserHolder userHolder(User user){ // superUser -> primary = true
//        UserHolder userHolder = new UserHolder();
//        userHolder.setUser(user);
//        return userHolder;
        return new UserHolder(user);
//    }
}

1、通过definitionBuilder.addPropertyReference(“user”, “superUser”);将类成员变量和xml配置文件中的bean关联。

运行结果

在这里插入图片描述

XML-Autowire方法 实现Bean配置

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>

<!--    <bean class="spring.ioc.dependency.injection.UserHolder" autowire="byName">-->
    <bean class="spring.ioc.dependency.injection.UserHolder" autowire="byType">
<!--        <property name="user" ref="superUser"/>  替换成 autowiring 模式-->
    </bean>

</beans>

通过配置文件 autowiring-dependency-setter-injection.xml 中的bean定义,采用 autowire=“byName”/"byType"实现自动绑定。

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

/**
 * ByName Autowiring 依赖 Setter 方法注入示例
 */
public class AutoWiringByNameDependencySetterInjectionDemo {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        String xmlResourcePath = "classpath:/META-INF/autowiring-dependency-setter-injection.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
        //依赖查找并且创建 Bean
        UserHolder userHolder = beanFactory.getBean(UserHolder.class);

        System.out.println(userHolder);
    }
}

直接getBean()获取即可。

运行结果

在这里插入图片描述

应用实例16

应用实例16延续应用实例15,主讲获取bean对象的3种手动constructor方法和2种自动方法:
1、XML-constructor-arg-ref方法;
2、构造函数(@Bean);
3、api方法;
4、XML-Autowire方法。

代码架构

在这里插入图片描述

XML-constructor-arg-ref 实现bean配置

xml配置文件dependency-constructor-injection.xml :

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>

    <bean class="spring.ioc.dependency.injection.UserHolder">
        <constructor-arg name="user" ref="superUser"/>
    </bean>

</beans>

1、通过import引用之前的xml配置文件内容;
2、定义bean UserHolder,并在属性配置中,使用“constructor-arg + ref”实现类的注入(引用);

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

/**
 * 基于 XML 资源的依赖 constructor 方法注入
 */
public class XmlDependencyConstructorInjectionDemo {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        String xmlResourcePath = "classpath:/META-INF/dependency-constructor-injection.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
        //依赖查找并且创建 Bean
        UserHolder userHolder = beanFactory.getBean(UserHolder.class);

        System.out.println(userHolder);
    }
}

通过getBean获取UserHolder的bean对象。在获取时通过setter方法将superUser对象赋值给user成员变量。

运行结果

在这里插入图片描述

构造函数(@Bean) 实现bean配置

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;

/**
 * 基于 XML 资源的依赖 constructor 方法注入
 */
public class AnnotationDependencyConstructorInjectionDemo {

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类)
        applicationContext.register(AnnotationDependencyConstructorInjectionDemo.class);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();


        //依赖查找并且创建 Bean
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);

        System.out.println(userHolder);

        //关闭应用上下文
        applicationContext.close();
    }

    @Bean
    public UserHolder userHolder(User user){
        return new UserHolder(user);
    }
}

通过@Bean注解定义bean,并通过构造函数或setter获得对象。

运行结果

在这里插入图片描述

api方法 实现bean配置

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 基于 API 注解的依赖 constructor 方法注入
 */
public class ApiDependencyConstructorInjectionDemo {

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 UserHolder 的 BeanDefinition
        BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
        //生成 UserHolder 的 BeanDefinition
        applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找并且创建 Bean
        UserHolder userHolder = applicationContext.getBean(UserHolder.class);

        System.out.println(userHolder);

        //关闭应用上下文
        applicationContext.close();
    }

    /**
     * 为 {@Link UserHolder} 生成 {@Link BeanDefinition}
     * @return
     */
    private static BeanDefinition createUserHolderBeanDefinition() {
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
        definitionBuilder.addConstructorArgReference("superUser");
        return definitionBuilder.getBeanDefinition();
    }

//    @Bean
//    public UserHolder userHolder(User user){ // superUser -> primary = true
//        UserHolder userHolder = new UserHolder();
//        userHolder.setUser(user);
//        return userHolder;
        return new UserHolder(user);
//    }
}

1、通过definitionBuilder.addConstructorArgReference(“superUser”);将类成员变量和xml配置文件中的bean关联。

运行结果

在这里插入图片描述

XML-Autowire方法 实现Bean配置

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>

<!--    <bean class="spring.ioc.dependency.injection.UserHolder" autowire="byName">-->
    <bean class="spring.ioc.dependency.injection.UserHolder" autowire="constructor">
<!--        <property name="user" ref="superUser"/>  替换成 autowiring 模式-->
    </bean>

</beans>```
通过配置文件 autowiring-dependency-constructor-injection.xml 中的bean定义,采用 autowire="constructor"实现自动绑定。

```java
package spring.ioc.dependency.injection;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

/**
 * ByName Autowiring 依赖 Constructor 方法注入示例
 */
public class AutoWiringConstructorDependencyConstructorInjectionDemo {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        String xmlResourcePath = "classpath:/META-INF/autowiring-dependency-setter-injection.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
        //依赖查找并且创建 Bean
        UserHolder userHolder = beanFactory.getBean(UserHolder.class);

        System.out.println(userHolder);
    }
}

直接getBean()获取即可。

运行结果

在这里插入图片描述

应用实例17

应用实例17延续应用实例16架构,主讲获取bean对象的2种注解配置方式:
1、@Autowire(通过属性);
2、@Resource (通过属性);
3、@Bean (通过方法。)

代码架构

在这里插入图片描述

AnnotationDependencyFieldInjectionDemo

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;

import javax.annotation.Resource;

/**
 * 基于 XML 资源的依赖字段方法注入
 */
public class AnnotationDependencyFieldInjectionDemo {

    @Autowired
    private UserHolder userHolder; //不接受static字段

    @Resource
    private UserHolder userholder2;

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(AnnotationDependencyFieldInjectionDemo.class);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找 AnnotationDependencyFieldInjectionDemo Bean
        AnnotationDependencyFieldInjectionDemo demo = applicationContext.getBean(AnnotationDependencyFieldInjectionDemo.class);

        //依赖查找并且创建 Bean
        UserHolder userHolder = demo.userHolder;
        System.out.println(userHolder);
        System.out.println(demo.userholder2);
        System.out.println(userHolder == demo.userholder2);

        //关闭应用上下文
        applicationContext.close();
    }

    @Bean
    public UserHolder userHolder(User user){
        return new UserHolder(user);
    }
}

通过@Autowire和@Resource实现自注入,然后通过bean类进行提取(按类型)。

运行结果

在这里插入图片描述

应用实例18

应用实例18延续应用实例17架构,主讲获取bean对象的2种注解配置方式(通过方法实现):
1、@Autowire(通过方法);
2、@Resource (通过方法);
3、@Bean (通过方法)。

代码架构

在这里插入图片描述

AnnotationDependencyMethodInjectionDemo

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;

import javax.annotation.Resource;

/**
 * 基于 XML 资源的依赖字段方法注入
 */
public class AnnotationDependencyMethodInjectionDemo {

    private UserHolder userHolder; //不接受static字段
    private UserHolder userholder2;

    @Autowired
    public void initUserHolder(UserHolder userHolder){
        this.userHolder = userHolder;
    }

    @Resource
    public void initUserHolder2(UserHolder userHolder2){
        this.userholder2 = userHolder2;
    }

    @Bean
    public UserHolder userHolder(User user){
        return new UserHolder(user);
    }

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(AnnotationDependencyMethodInjectionDemo.class);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找 AnnotationDependencyFieldInjectionDemo Bean
        AnnotationDependencyMethodInjectionDemo demo = applicationContext.getBean(AnnotationDependencyMethodInjectionDemo.class);

        //依赖查找并且创建 Bean
        UserHolder userHolder = demo.userHolder;
        System.out.println(userHolder);
        System.out.println(demo.userholder2);
        System.out.println(userHolder == demo.userholder2);

        //关闭应用上下文
        applicationContext.close();
    }
}

通过在类似set方法前配置@Autowire和@Resource,同样可以实现类对象注入。

应用实例19

应用实例19延续应用实例18架构,主讲通过实现BeanFactoryAware和ApplicationContextAware接口完成接口回调注入。

代码架构

在这里插入图片描述

AwareInterfaceDependencyInjectionDemo

package spring.ioc.dependency.injection;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

/**
 * 基于 Aware 接口回调的依赖注入示例
 */
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {

    private static BeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        context.register(AwareInterfaceDependencyInjectionDemo.class);

        //启动应用上下文
        context.refresh();


        System.out.println(beanFactory == context.getBeanFactory());
        System.out.println(applicationContext == context);

        //关闭应用上下文
        context.close();
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;
    }
}

通过实现BeanFactoryAware和ApplicationContextAware接口的set方法,实现bean对象接口回调。

运行结果

在这里插入图片描述

应用实例20

应用实例20主讲枚举类型和资源类型的自动注入。

代码架构

在这里插入图片描述

City 枚举类

package springtest.ioc.overview.enums;

/**
 * 城市枚举
 */
public enum City {

    BEIJING,
    SHANGHAI,
    GUANGZHOU,
    SHENZHEN
}

包含北京、上海、广州和深圳。

User 增加城市和资源属性

package springtest.ioc.overview.domain;

import org.springframework.core.io.Resource;
import springtest.ioc.overview.enums.City;

/**
 * 用户类
 */
public class User {

    private Long id;
    private String name;
    private City city;
    private Resource configFileLocation;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public City getCity() {
        return city;
    }

    public void setCity(City city) {
        this.city = city;
    }

    public Resource getConfigFileLocation() {
        return configFileLocation;
    }

    public void setConfigFileLocation(Resource configFileLocation) {
        this.configFileLocation = configFileLocation;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", city=" + city +
                ", configFileLocation=" + configFileLocation +
                '}';
    }

    /**
     * 静态方法构建 bean
     * @return
     */
    public static User createUser(){
        User user = new User();
        user.setId(1L);
        user.setName("xiaohhong");
        return user;
    }
}

dependency-lookup-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">


    <bean id="user" class="springtest.ioc.overview.domain.User">
        <property name="id" value="1"/>
        <property name="name" value="xiaoming"/>
        <property name="city" value="SHENZHEN"/>
        <property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
    </bean>

    <bean id="superUser" class="springtest.ioc.overview.domain.SuperUser" parent="user" primary="true">
        <property name="address" value="Hangzhou"/>
    </bean>

    <bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
        <property name="targetBeanName" value="user"/>
    </bean>


</beans>

增加 city 和 congifFileLocation配置。

DependencyLookupDemo

package springtest.ioc.overview.dependency.lookup;


import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.annotation.Super;
import springtest.ioc.overview.domain.SuperUser;
import springtest.ioc.overview.domain.User;

import java.util.Map;

/**
 * 依赖查找示例
 * 1、通过名称查找
 * 2、通过类型查找
 */
public class DependencyLookupDemo {

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

    public static void lookupInRealTime(BeanFactory beanFactory) {
        User user = (User) beanFactory.getBean("user");
        System.out.println("实时查找:" + user);
    }

    private static void lookInLazy(BeanFactory beanFactory) {
        ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
        User user = objectFactory.getObject();
        System.out.println("延迟查找:" + user);
    }

    private static void lookupByType(BeanFactory beanFactory) {
        User user = beanFactory.getBean(User.class);
        System.out.println("实时(类型)查找:" + user);
    }

    private static void lookupByColleactionType(BeanFactory beanFactory) {
        if (beanFactory instanceof ListableBeanFactory) {
            ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
            Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
            System.out.println("实时(集合类型)查找:" + users);
        }
    }

    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的用户集合:" + users);
        }
    }
}

运行结果

在这里插入图片描述

应用实例21

应用实例21承接应用实例20,主讲数组和集合类型注入,通过City数组和集合来举例。

User

package springtest.ioc.overview.domain;

import org.springframework.core.io.Resource;
import springtest.ioc.overview.enums.City;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * 用户类
 */
public class User {

    private Long id;
    private String name;
    private City city;
    private City[] workCities;
    private List<City> lifeCities;
    private Set<City> friendCities;
    private Resource configFileLocation;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public City getCity() {
        return city;
    }

    public void setCity(City city) {
        this.city = city;
    }

    public City[] getWorkCities() {
        return workCities;
    }

    public void setWorkCities(City[] workCities) {
        this.workCities = workCities;
    }

    public List<City> getLifeCities() {
        return lifeCities;
    }

    public void setLifeCities(List<City> lifeCities) {
        this.lifeCities = lifeCities;
    }

    public Set<City> getFriendCities() {
        return friendCities;
    }

    public void setFriendCities(Set<City> friendCities) {
        this.friendCities = friendCities;
    }

    public Resource getConfigFileLocation() {
        return configFileLocation;
    }

    public void setConfigFileLocation(Resource configFileLocation) {
        this.configFileLocation = configFileLocation;
    }


    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", city=" + city +
                ", workCities=" + Arrays.toString(workCities) +
                ", lifeCities=" + lifeCities +
                ", friendCities=" + friendCities +
                ", configFileLocation=" + configFileLocation +
                '}';
    }

    /**
     * 静态方法构建 bean
     * @return
     */
    public static User createUser(){
        User user = new User();
        user.setId(1L);
        user.setName("xiaohhong");
        return user;
    }
}

workCities是数组类型,lifeCities是List集合,friendCities是Set集合。

dependency-lookup-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">


    <bean id="user" class="springtest.ioc.overview.domain.User">
        <property name="id" value="1"/>
        <property name="name" value="xiaoming"/>
        <property name="city" value="SHENZHEN"/>
        <property name="workCities" value="BEIJING, SHANGHAI"/>
        <property name="lifeCities" value="SHANGHAI, GUANGZHOU"/>
        <property name="friendCities">
            <set>
                <value>GUANGZHOU</value>
                <value>SHENZHEN</value>
            </set>
        </property>
        <property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
    </bean>

    <bean id="superUser" class="springtest.ioc.overview.domain.SuperUser" parent="user" primary="true">
        <property name="address" value="Hangzhou"/>
    </bean>

    <bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
        <property name="targetBeanName" value="user"/>
    </bean>


</beans>

数组和集合都可以在property中的value上直接用逗号分割就可以表示集合元素,或者在property下增加list或set子节点来注入集合元素。

调试类 DependencyLookupDemo

package springtest.ioc.overview.dependency.lookup;


import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.annotation.Super;
import springtest.ioc.overview.domain.SuperUser;
import springtest.ioc.overview.domain.User;

import java.util.Map;

/**
 * 依赖查找示例
 * 1、通过名称查找
 * 2、通过类型查找
 */
public class DependencyLookupDemo {

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

    public static void lookupInRealTime(BeanFactory beanFactory) {
        User user = (User) beanFactory.getBean("user");
        System.out.println("实时查找:" + user);
    }

    private static void lookInLazy(BeanFactory beanFactory) {
        ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
        User user = objectFactory.getObject();
        System.out.println("延迟查找:" + user);
    }

    private static void lookupByType(BeanFactory beanFactory) {
        User user = beanFactory.getBean(User.class);
        System.out.println("实时(类型)查找:" + user);
    }

    private static void lookupByColleactionType(BeanFactory beanFactory) {
        if (beanFactory instanceof ListableBeanFactory) {
            ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
            Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
            System.out.println("实时(集合类型)查找:" + users);
        }
    }

    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的用户集合:" + users);
        }
    }
}

运行结果

在这里插入图片描述

应用实例22

应用实例22继承应用实例21,主讲通过@Autowire、@Qualifier和继承自@Qualifier注解的注入和使用。

代码架构

在这里插入图片描述

@UserGroup

package spring.ioc.dependency.injection.annotation;

import org.springframework.beans.factory.annotation.Qualifier;

import java.lang.annotation.*;

/**
 * 用户组注解,扩展 @Qualifier
 */

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface UserGroup {
}

@UserGroup开头的定义直接拷贝自@Qualifier,同时在前面也增加了@Qualifier,表示@UserGroup继承了@Qualifier特性。

QualifierAnnotationDependencyInjectionDemo

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import spring.ioc.dependency.injection.annotation.UserGroup;
import springtest.ioc.overview.domain.User;

import java.util.Collection;

/**
 * Qualifier 注解依赖注入
 */
public class QualifierAnnotationDependencyInjectionDemo {

    @Autowired
    private User user;  //SuperUser

    @Autowired
    @Qualifier("user")  //指定 Bean 的名称或 ID
    private User namedUser;

    //整体应用上下文存在 4个 User 类型的 Bean
    //superUser
    //user
    //user1 -> @Qualifier
    //user2 -> @Qualifier

    @Autowired
    private Collection<User> allUsers;  //2 Bean -> user + superUser

    @Autowired
    @Qualifier
    private Collection<User> qualifierUsers;  //2 Bean -> user1 + user2 + user3 + user4

    @Autowired
    @UserGroup
    private Collection<User> userGroupUsers;  //2 Bean -> user3 + user4

    @Bean
    @Qualifier
    public User user1() {
        return createUser(7L);
    }

    @Bean
    @Qualifier
    public User user2() {
        return createUser(8L);
    }

    @Bean
    @UserGroup
    public User user3() {
        return createUser(9L);
    }

    @Bean
    @UserGroup
    public User user4() {
        return createUser(10L);
    }

    private static User createUser(Long id) {
        User user = new User();
        user.setId(id);
        return user;
    }


    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(QualifierAnnotationDependencyInjectionDemo.class);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找 AnnotationDependencyFieldInjectionDemo Bean
        QualifierAnnotationDependencyInjectionDemo demo = applicationContext.getBean(QualifierAnnotationDependencyInjectionDemo.class);

        //输出 superUser Bean
        System.out.println("demo.user = " + demo.user);
        //输出 user Bean
        System.out.println("demo.nanmedUser = " + demo.namedUser);
        //输出 allUsers Bean
        System.out.println("demo.allUsers = " + demo.allUsers);
        //输出 qualifierUsers Bean
        System.out.println("demo.qualifierUsers = " + demo.qualifierUsers);
        //输出 userGroupUsers Bean
        System.out.println("demo.userGroupUsers = " + demo.userGroupUsers);

        //关闭应用上下文
        applicationContext.close();
    }
}

可以看出:
1、@Autowire 可以自动注入类型,只是注入的是最高优先级;
2、@Autowire 和 @Qualifier一起使用,并在@Qualifier中指定需要注入的Bean id;
3、在注入集合时,@Autowire 会将相同类型的、并且没有标注其他注解的Bean全部注入结合中(不包括使用了@Qualifier 和 @UserGroup的bean);
4、在注入集合时,@Autowire 和 @Qualifier一起使用,会将相同类型的、并且标注了@Qualifier的Bean全部注入结合中(包括使用了@UserGroup的bean);
5、在注入集合时,@Autowire 和 @UserGroup一起使用,会将相同类型的、并且标注了@UserGroup的Bean全部注入结合中(不包括使用了@Qualifier的bean);

运行结果

demo.user = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.nanmedUser = User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.allUsers = [User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}, SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}]
demo.qualifierUsers = [User{id=7, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, User{id=8, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, User{id=9, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, User{id=10, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}]
demo.userGroupUsers = [User{id=9, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, User{id=10, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}]

Process finished with exit code 0

应用实例23

应用实例23继承应用实例22,主讲通过ObjectProvider实现延迟注入。

代码架构

在这里插入图片描述

LazyAnnotationDependencyInjectionDemo

package spring.ioc.dependency.injection;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import spring.ioc.dependency.injection.annotation.UserGroup;
import springtest.ioc.overview.domain.User;

import java.util.Collection;
import java.util.Set;

/**
 * Qualifier 注解依赖注入
 */
public class LazyAnnotationDependencyInjectionDemo {

    @Autowired
    private User user;  //SuperUser

    @Autowired
    private ObjectProvider<User> objectProvider;    //如果有多个对象,不会报错

    @Autowired
    private ObjectFactory<Set<User>> objectFactory; //如果有多个对象,会报错


    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(LazyAnnotationDependencyInjectionDemo.class);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找 AnnotationDependencyFieldInjectionDemo Bean
        LazyAnnotationDependencyInjectionDemo demo = applicationContext.getBean(LazyAnnotationDependencyInjectionDemo.class);

        //输出 superUser Bean
        System.out.println("demo.user = " + demo.user);
        //输出 user Bean
        System.out.println("demo.objectProvider = " + demo.objectProvider.getObject());
        demo.objectProvider.forEach(System.out::println);

        //输出 user Bean
        System.out.println("demo.objectFactory = " + demo.objectFactory.getObject());

        //关闭应用上下文
        applicationContext.close();
    }
}

运行结果

demo.user = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.objectProvider = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.objectFactory = [User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}, SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}]

Process finished with exit code 0

应用实例24

应用实例24继承应用实例23,主讲实现延迟注入的原发分析。

代码架构

在这里插入图片描述

AnnotationDependencyInjectionResolutionDemo

package spring.ioc.dependency.injection;

import com.oracle.tools.packager.mac.MacAppBundler;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import springtest.ioc.overview.domain.User;

import javax.inject.Inject;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
 * 注解依赖驱动的注入处理过程
 */
public class AnnotationDependencyInjectionResolutionDemo {

    @Autowired          // 依赖查找(处理)
    private User user;  // DependencyDescriptor ->
                        // 必须(required=true)
                        // 实时注入(eager=true)
                        // 通过类型(User.class)
                        // 字段名称("user")
                        // 是否 (primary=true)

    @Autowired                      // 集合类型的依赖注入
    private Map<String, User> users; //user superUser

    @Autowired
    private Optional<User> optionalUser;    //user

    @Inject
    private User injectUser;


    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找 AnnotationDependencyFieldInjectionDemo Bean
        AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);

        //输出 superUser Bean
        System.out.println("demo.user = " + demo.user);
        System.out.println("demo.injectUser = " + demo.injectUser);
        //输出 user Bean
        System.out.println("demo.user = " + demo.users);
        //输出 superUser Bean
        System.out.println("demo.optionalUser = " + demo.optionalUser);



        //关闭应用上下文
        applicationContext.close();
    }
}

运行结果

demo.user = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.injectUser = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.user = {user=User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}, superUser=SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}}
demo.optionalUser = Optional[SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}]

Process finished with exit code 0

应用实例25

应用实例25主讲实现自定义依赖注入的方法。

代码架构

在这里插入图片描述

MyAutowired注解

package spring.ioc.dependency.injection.annotation;

import org.springframework.beans.factory.annotation.Autowired;

import java.lang.annotation.*;

/**
 * 自定义注解(元标注 @Autowired)
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MyAutowired {
    boolean required() default true;
}

@MyAutowired主要继承Autowired,作用和@Autowired一样。

InjectedUser注解

package spring.ioc.dependency.injection.annotation;

import java.lang.annotation.*;

/**
 * 自定义依赖注入注解
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InjectedUser {
}

@InjectedUser注解直接赋值@Injected,作用相同。

AnnotationDependencyInjectionResolutionDemo

package spring.ioc.dependency.injection;

import com.oracle.tools.packager.mac.MacAppBundler;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import spring.ioc.dependency.injection.annotation.InjectedUser;
import spring.ioc.dependency.injection.annotation.MyAutowired;
import springtest.ioc.overview.domain.User;

import javax.inject.Inject;
import java.lang.annotation.Annotation;
import java.util.*;

import static java.util.Arrays.asList;
import static org.springframework.context.annotation.AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME;

/**
 * 注解依赖驱动的注入处理过程
 */
public class AnnotationDependencyInjectionResolutionDemo {

    @Autowired          // 依赖查找(处理)
    private User user;  // DependencyDescriptor ->
                        // 必须(required=true)
                        // 实时注入(eager=true)
                        // 通过类型(User.class)
                        // 字段名称("user")
                        // 是否 (primary=true)

    @Autowired                      // 集合类型的依赖注入
    private Map<String, User> users; //user superUser

    @MyAutowired
    private Optional<User> optionalUser;    //user

    @Inject
    private User injectUser;

    @InjectedUser
    private User myInjectedUser;

    //方法一
//    @Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
//    public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
//        AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
//        // @Autowired + @Inject + 新注解 @InjectedUser
//        Set<Class<? extends Annotation>> autowiredAnnotationTypes =
//                new LinkedHashSet<>(asList(Autowired.class, Inject.class, InjectedUser.class));
//        beanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
//        return beanPostProcessor;
//    }

    //方法二
    @Bean()
    @Order(Ordered.LOWEST_PRECEDENCE - 3)
    public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
        AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
        beanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
        return beanPostProcessor;
    }

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);

        String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载 XML 资源,解析并生成 BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找 AnnotationDependencyFieldInjectionDemo Bean
        AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);

        //输出 superUser Bean
        System.out.println("demo.user = " + demo.user);
        System.out.println("demo.injectUser = " + demo.injectUser);
        //输出 user Bean
        System.out.println("demo.user = " + demo.users);
        //输出 superUser Bean
        System.out.println("demo.optionalUser = " + demo.optionalUser);
        //输出 superUser Bean
        System.out.println("demo.myInjectedUser = " + demo.myInjectedUser);



        //关闭应用上下文
        applicationContext.close();
    }
}

两种方法实现依赖注入:一种是通过组合将3个注释加入对象中,这样3个对象都可执行依赖注入;另一种只注入@InjectUser来实现依赖注入,通过增加@order来指定执行顺序(定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序)。

应用实例26

应用实例26主讲依赖注入和依赖查找在来源上的查边:依赖注入比依赖查找多一个非Spring管理机构。

代码架构

在这里插入图片描述

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springtest</artifactId>
        <groupId>springtest</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dependency-source</artifactId>

    <dependencies>
        <!-- Spring IoC 核心模块 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <!-- 复用 ioc-container-overview</artifactId> -->
        <dependency>
            <groupId>${groupId}</groupId>
            <artifactId>ioc-container-overview</artifactId>
            <version>${version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

源代码中关于4个类型的依赖注入操作

在这里插入图片描述

DependencySourceDemo

package springtest.dependency.source;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.core.io.ResourceLoader;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * 依赖来源示例
 */
public class DependencySourceDemo {

    /**
     * 注入在 postProcessProperties 方法执行,早于 setter 注入,也早于@PostConstruct
     */

    @Autowired
    private BeanFactory beanFactory;

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    //依赖注入比依赖查找多一项
    @PostConstruct
    public void initByInjection() {
        System.out.println("beanFactory == applicationContext:" + (beanFactory == applicationContext));
        System.out.println("beanFactory == applicationContext.getAutowireCapableBeanFactory():" + (beanFactory == applicationContext.getAutowireCapableBeanFactory()));
        System.out.println("resourceLoader == applicationContext:" + (resourceLoader == applicationContext));
        System.out.println("applicationEventPublisher == applicationContext:" + (applicationEventPublisher == applicationContext));
    }

    @PostConstruct
    public void initByLookup() {
        getBean(BeanFactory.class);
        getBean(ResourceLoader.class);
        getBean(ApplicationContext.class);
        getBean(ApplicationEventPublisher.class);
    }

    private <T> T getBean(Class<T> beanType) {
        try {
            return beanFactory.getBean(beanType);
        } catch (NoSuchBeanDefinitionException e) {
            System.out.println("当前类型:" + beanType.getName() + "无法在BeanFactory中找到。");
        }
        return null;
    }


    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(DependencySourceDemo.class);

        //启动应用上下文
        applicationContext.refresh();

        //依赖查找 DependencySourceDemo Bean
        DependencySourceDemo demo = applicationContext.getBean(DependencySourceDemo.class);

        //关闭应用上下文
        applicationContext.close();
    }
}

运行结果

在这里插入图片描述

应用实例27

应用实例27主讲通过配置文件实现依赖注入。

代码架构

在这里插入图片描述

配置文件 default.properties

user.id = 1
usr.name = 小马哥

user.resource = classpath:/META-INF/default.properties

ExternalConfigurationDependencySourceDemo

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package springtest.dependency.source;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;

/**
 * 外部化配置作为依赖来源示例
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
@Configuration
@PropertySource(value = "classpath:/META-INF/default.properties", encoding = "UTF-8")
public class ExternalConfigurationDependencySourceDemo {

    @Value("${user.id:-1}")
    private Long id;

    @Value("${usr.name}")
    private String name;

    @Value("${user.resource:classpath:/default.properties}")
    private Resource resource;

    public static void main(String[] args) {

        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类) -> Spring Bean
        applicationContext.register(ExternalConfigurationDependencySourceDemo.class);

        // 启动 Spring 应用上下文
        applicationContext.refresh();

        // 依赖查找 ExternalConfigurationDependencySourceDemo Bean
        ExternalConfigurationDependencySourceDemo demo = applicationContext.getBean(ExternalConfigurationDependencySourceDemo.class);

        System.out.println("demo.id = " + demo.id);
        System.out.println("demo.name = " + demo.name);
        System.out.println("demo.resource = " + demo.resource);

        // 显示地关闭 Spring 应用上下文
        applicationContext.close();
    }
}

应用实例28

应用实例28主讲singleton和prototype的有效范围。

代码架构

在这里插入图片描述

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springtest</artifactId>
        <groupId>springtest</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>bean-scope</artifactId>

    <dependencies>
        <!-- Spring IoC 核心模块 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <!-- 复用 ioc-container-overview</artifactId> -->
        <dependency>
            <groupId>${groupId}</groupId>
            <artifactId>ioc-container-overview</artifactId>
            <version>${version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

复用之前的代码配置。

User定义

package springtest.ioc.overview.domain;

import jdk.nashorn.internal.objects.annotations.Constructor;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.core.io.Resource;
import springtest.ioc.overview.enums.City;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * 用户类
 */
public class User implements BeanNameAware {

    private Long id;
    private String name;
    private City city;
    private City[] workCities;
    private List<City> lifeCities;
    private Set<City> friendCities;
    private Resource configFileLocation;
    /**
     * 当前 Bean 的名称
     */
    private transient String beanName;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public City getCity() {
        return city;
    }

    public void setCity(City city) {
        this.city = city;
    }

    public City[] getWorkCities() {
        return workCities;
    }

    public void setWorkCities(City[] workCities) {
        this.workCities = workCities;
    }

    public List<City> getLifeCities() {
        return lifeCities;
    }

    public void setLifeCities(List<City> lifeCities) {
        this.lifeCities = lifeCities;
    }

    public Set<City> getFriendCities() {
        return friendCities;
    }

    public void setFriendCities(Set<City> friendCities) {
        this.friendCities = friendCities;
    }

    public Resource getConfigFileLocation() {
        return configFileLocation;
    }

    public void setConfigFileLocation(Resource configFileLocation) {
        this.configFileLocation = configFileLocation;
    }


    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", city=" + city +
                ", workCities=" + Arrays.toString(workCities) +
                ", lifeCities=" + lifeCities +
                ", friendCities=" + friendCities +
                ", configFileLocation=" + configFileLocation +
                '}';
    }

    /**
     * 静态方法构建 bean
     * @return
     */
    public static User createUser(){
        User user = new User();
        user.setId(1L);
        user.setName("xiaohhong");
        return user;
    }

    @PostConstruct
    public void init(){
        System.out.println("beanName:" + beanName + ",用户对象初始化...");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("beanName:" + beanName + ",用户对象销毁...");
    }

    @Override
    public void setBeanName(String s) {
        this.beanName = s;
    }
}

其中:
1、BeanNameAware接口主要用来设置beanName,这里需要自行定义一个beanName对象。代码中在定义beanName的时候在前面增加了transient,表示这个属性不会进行序列化;
2、@PostContruct和@PreDestroy注解分别表示初始化和销毁,此处主要用于打印bean初始化和销毁的时间点,方便理解;

BeanScopeDemo

package springtest.bean.scope;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ResourceLoader;
import springtest.ioc.overview.domain.User;

import javax.annotation.PostConstruct;
import java.util.Map;

/**
 * 依赖来源示例
 */
public class BeanScopeDemo implements DisposableBean {

    @Bean
    // 默认 scope 就是 singletion
    public static User singletonUser(){
        return createUser();
    }

    @Bean
//    @Scope("prototype")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public static User prototypeUser(){
        return createUser();
    }


    private static User createUser(){
        User user = new User();
        user.setId(System.nanoTime());
        return user;
    }

    @Autowired
    @Qualifier("singletonUser")
    private User singletonUser;

    @Autowired
    @Qualifier("singletonUser")
    private User singletonUser1;

    @Autowired
    @Qualifier("prototypeUser")
    private User prototypeUser;

    @Autowired
    @Qualifier("prototypeUser")
    private User prototypeUser1;

    @Autowired
    @Qualifier("prototypeUser")
    private User prototypeUser2;

    @Autowired
    private Map<String, User> users;

    @Autowired
    private ConfigurableListableBeanFactory beanFactory; // Resolvable Dependency

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(BeanScopeDemo.class);

        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.addBeanPostProcessor(new BeanPostProcessor() {

                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    System.out.printf("%s Bean 名称:%s 在初始化后回调...%n", bean.getClass().getName(), beanName);
                    return bean;
                }
            });
        });

        //启动应用上下文
        applicationContext.refresh();


        //结论一:
        //singleton Bean 无论是依赖查找还是注入,均为同一个对象
        //prototype Bean 无论是依赖查找还是注入,均生成新的对象

        //结论二:
        //如果依赖注入集合型对象时,singleton Bean和prototype Bean均只存在一份
        //prototype Bean有别于其他地方的依赖注入prototype Bean

        // 结论三:
        // 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
        // 不过仅 Singleton Bean 会执行销毁方法回调

        scopeBeanByLookip(applicationContext);
        scopeBeanByInjection(applicationContext);


        //关闭应用上下文
        applicationContext.close();

    }



    private static void scopeBeanByLookip(AnnotationConfigApplicationContext applicationContext) {

        for (int i = 0; i < 3; i++) {
            // singleton 是共享型 bean 对象
            User singleton = applicationContext.getBean("singletonUser", User.class);
            System.out.println("singletonUser = " + singleton);

            // prototype 是独享型 bean 对象
            User prototype = applicationContext.getBean("prototypeUser", User.class);
            System.out.println("prototypeUser = " + prototype);
        }

    }

    private static void scopeBeanByInjection(AnnotationConfigApplicationContext applicationContext) {
        BeanScopeDemo beanScopeDemo = applicationContext.getBean(BeanScopeDemo.class);

        System.out.println("beanScopeDemo.singletonUser = " + beanScopeDemo.singletonUser);
        System.out.println("beanScopeDemo.singletonUser1 = " + beanScopeDemo.singletonUser1);

        System.out.println("beanScopeDemo.prototypeUser = " + beanScopeDemo.prototypeUser);
        System.out.println("beanScopeDemo.prototypeUser1 = " + beanScopeDemo.prototypeUser1);
        System.out.println("beanScopeDemo.prototypeUser2 = " + beanScopeDemo.prototypeUser2);

        System.out.println("beanScopeDemo.users = " + beanScopeDemo.users);
    }

    @Override
    public void destroy() throws Exception {

        System.out.println("当前 BeanScopeDemo Bean 正在销毁中...");

        this.prototypeUser.destroy();
        this.prototypeUser1.destroy();
        this.prototypeUser1.destroy();
        this.prototypeUser2.destroy();
        // 获取 BeanDefinition
        for (Map.Entry<String, User> entry : this.users.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            if (beanDefinition.isPrototype()) { // 如果当前 Bean 是 prototype scope
                User user = entry.getValue();
                user.destroy();
            }
        }

        System.out.println("当前 BeanScopeDemo Bean 销毁完成");
    }
}

结论:
结论一:
singleton Bean 无论是依赖查找还是注入,均为同一个对象
prototype Bean 无论是依赖查找还是注入,均生成新的对象
结论二:
如果依赖注入集合型对象时,singleton Bean和prototype Bean均只存在一份
prototype Bean有别于其他地方的依赖注入prototype Bean
结论三:
无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
不过仅 Singleton Bean 会执行销毁方法回调

其中:
1、DisposableBean用于对象类销毁时的操作,实现destroy方法。

运行结果

org.springframework.context.event.EventListenerMethodProcessor Bean 名称:org.springframework.context.event.internalEventListenerProcessor 在初始化后回调...
org.springframework.context.event.DefaultEventListenerFactory Bean 名称:org.springframework.context.event.internalEventListenerFactory 在初始化后回调...
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor Bean 名称:org.springframework.context.annotation.internalAutowiredAnnotationProcessor 在初始化后回调...
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor Bean 名称:org.springframework.context.annotation.internalCommonAnnotationProcessor 在初始化后回调...
beanName:singletonUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:singletonUser 在初始化后回调...
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
springtest.bean.scope.BeanScopeDemo Bean 名称:beanScopeDemo 在初始化后回调...
singletonUser = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
prototypeUser = User{id=594157593713595, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
singletonUser = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
prototypeUser = User{id=594157596412233, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
singletonUser = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
prototypeUser = User{id=594157597510228, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.singletonUser = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.singletonUser1 = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.prototypeUser = User{id=594157537496854, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.prototypeUser1 = User{id=594157543965313, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.prototypeUser2 = User{id=594157547245936, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.users = {singletonUser=User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, prototypeUser=User{id=594157559292355, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}}
当前 BeanScopeDemo Bean 正在销毁中...
beanName:prototypeUser,用户对象销毁...
beanName:prototypeUser,用户对象销毁...
beanName:prototypeUser,用户对象销毁...
beanName:prototypeUser,用户对象销毁...
beanName:prototypeUser,用户对象销毁...
当前 BeanScopeDemo Bean 销毁完成
beanName:singletonUser,用户对象销毁...

Process finished with exit code 0

应用实例29

应用实例29主讲scope。

代码架构

在这里插入图片描述

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springtest</artifactId>
        <groupId>springtest</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>bean-scope</artifactId>
    <packaging>war</packaging>

    <dependencies>

        <!-- Spring IoC 核心模块 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <!-- 复用 ioc-container-overview</artifactId> -->
        <dependency>
            <groupId>${groupId}</groupId>
            <artifactId>ioc-container-overview</artifactId>
            <version>${version}</version>
        </dependency>

        <!-- 使用 Servlet 3.1 API -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
            <version>2.2.0.RELEASE</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
            <version>2.2.0.RELEASE</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <!-- Tomcat 8 Maven 插件用于构建可执行 war -->
            <!-- https://mvnrepository.com/artifact/org.apache.tomcat.maven/tomcat8-maven-plugin -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat8-maven-plugin</artifactId>
                <version>3.0-r1655215</version>
                <executions>
                    <execution>
                        <id>tomcat-run</id>
                        <goals>
                            <!-- 最终打包成可执行的jar包 -->
                            <goal>exec-war-only</goal>
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <!-- ServletContext 路径 -->
                            <path>/</path>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <pluginRepositories>
        <pluginRepository>
            <!-- tomcat8-maven-plugin 所在仓库 -->
            <id>Alfresco</id>
            <name>Alfresco Repository</name>
            <url>https://artifacts.alfresco.com/nexus/content/repositories/public/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

</project>

dispatch-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 激活 Spring 注解驱动 -->
    <context:component-scan base-package="springtest.bean.scope"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

index.jsp

<?xml version="1.0" encoding="UTF-8" ?>
<jsp:directive.page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" />
<html>
    <head>
        <link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>
    </head>
    <body>
        \${userObject.name} : ${userObject.name}
        \${applicationScope['scopedTarget.user'].name} : ${applicationScope['scopedTarget.user'].name}
    </body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

WebConfiguration

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package springtest.bean.scope.web;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.annotation.ApplicationScope;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import springtest.ioc.overview.domain.User;

/**
 * Web MVC 配置类
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
@Configuration
@EnableWebMvc
public class WebConfiguration {

    @Bean
//    @RequestScope
//    @SessionScope
    @ApplicationScope
    public User user() {
        User user = new User();
        user.setId(1L);
        user.setName("小马哥");
        return user;
    }

}

IndexController

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package springtest.bean.scope.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import springtest.ioc.overview.domain.User;

/**
 * 首页 Spring Web MVC Controller
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
@Controller
public class IndexController {

    @Autowired
    private User user; // CGLIB 代理后对象(不变的)

    @GetMapping("/index.html")
    public String index(Model model) {
        // JSP EL 变量搜索路径 page -> request -> session -> application(ServletContext)
        // userObject -> 渲染上下文
        // user 对象存在 ServletContext,上下文名称:scopedTarget.user == 新生成 Bean 名称
        model.addAttribute("userObject", user);
        return "index";
    }
}

BeanScopeDemo

package springtest.bean.scope;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ResourceLoader;
import springtest.ioc.overview.domain.User;

import javax.annotation.PostConstruct;
import java.util.Map;

/**
 * 依赖来源示例
 */
public class BeanScopeDemo implements DisposableBean {

    @Bean
    // 默认 scope 就是 singletion
    public static User singletonUser(){
        return createUser();
    }

    @Bean
//    @Scope("prototype")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public static User prototypeUser(){
        return createUser();
    }


    private static User createUser(){
        User user = new User();
        user.setId(System.nanoTime());
        return user;
    }

    @Autowired
    @Qualifier("singletonUser")
    private User singletonUser;

    @Autowired
    @Qualifier("singletonUser")
    private User singletonUser1;

    @Autowired
    @Qualifier("prototypeUser")
    private User prototypeUser;

    @Autowired
    @Qualifier("prototypeUser")
    private User prototypeUser1;

    @Autowired
    @Qualifier("prototypeUser")
    private User prototypeUser2;

    @Autowired
    private Map<String, User> users;

    @Autowired
    private ConfigurableListableBeanFactory beanFactory; // Resolvable Dependency

    public static void main(String[] args) {
        //创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册 Configuration Class (配置类) -> Spring Bean
        applicationContext.register(BeanScopeDemo.class);

        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.addBeanPostProcessor(new BeanPostProcessor() {

                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    System.out.printf("%s Bean 名称:%s 在初始化后回调...%n", bean.getClass().getName(), beanName);
                    return bean;
                }
            });
        });

        //启动应用上下文
        applicationContext.refresh();


        //结论一:
        //singleton Bean 无论是依赖查找还是注入,均为同一个对象
        //prototype Bean 无论是依赖查找还是注入,均生成新的对象

        //结论二:
        //如果依赖注入集合型对象时,singleton Bean和prototype Bean均只存在一份
        //prototype Bean有别于其他地方的依赖注入prototype Bean

        // 结论三:
        // 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
        // 不过仅 Singleton Bean 会执行销毁方法回调

        scopeBeanByLookip(applicationContext);
        scopeBeanByInjection(applicationContext);


        //关闭应用上下文
        applicationContext.close();

    }



    private static void scopeBeanByLookip(AnnotationConfigApplicationContext applicationContext) {

        for (int i = 0; i < 3; i++) {
            // singleton 是共享型 bean 对象
            User singleton = applicationContext.getBean("singletonUser", User.class);
            System.out.println("singletonUser = " + singleton);

            // prototype 是独享型 bean 对象
            User prototype = applicationContext.getBean("prototypeUser", User.class);
            System.out.println("prototypeUser = " + prototype);
        }

    }

    private static void scopeBeanByInjection(AnnotationConfigApplicationContext applicationContext) {
        BeanScopeDemo beanScopeDemo = applicationContext.getBean(BeanScopeDemo.class);

        System.out.println("beanScopeDemo.singletonUser = " + beanScopeDemo.singletonUser);
        System.out.println("beanScopeDemo.singletonUser1 = " + beanScopeDemo.singletonUser1);

        System.out.println("beanScopeDemo.prototypeUser = " + beanScopeDemo.prototypeUser);
        System.out.println("beanScopeDemo.prototypeUser1 = " + beanScopeDemo.prototypeUser1);
        System.out.println("beanScopeDemo.prototypeUser2 = " + beanScopeDemo.prototypeUser2);

        System.out.println("beanScopeDemo.users = " + beanScopeDemo.users);
    }

    @Override
    public void destroy() throws Exception {

        System.out.println("当前 BeanScopeDemo Bean 正在销毁中...");

        this.prototypeUser.destroy();
        this.prototypeUser1.destroy();
        this.prototypeUser1.destroy();
        this.prototypeUser2.destroy();
        // 获取 BeanDefinition
        for (Map.Entry<String, User> entry : this.users.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            if (beanDefinition.isPrototype()) { // 如果当前 Bean 是 prototype scope
                User user = entry.getValue();
                user.destroy();
            }
        }

        System.out.println("当前 BeanScopeDemo Bean 销毁完成");
    }
}

ThreadLocalScope

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package springtest.bean.scope;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.NonNull;

import java.util.HashMap;
import java.util.Map;

/**
 * ThreadLocal 级别 Scope
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class ThreadLocalScope implements Scope {

    public static final String SCOPE_NAME = "thread-local";

    private final NamedThreadLocal<Map<String, Object>> threadLocal = new NamedThreadLocal("thread-local-scope") {

        public Map<String, Object> initialValue() {
            return new HashMap<>();
        }
    };

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {

        // 非空
        Map<String, Object> context = getContext();

        Object object = context.get(name);

        if (object == null) {
            object = objectFactory.getObject();
            context.put(name, object);
        }

        return object;
    }

    @NonNull
    private Map<String, Object> getContext() {
        return threadLocal.get();
    }

    @Override
    public Object remove(String name) {
        Map<String, Object> context = getContext();
        return context.remove(name);
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        // TODO
    }

    @Override
    public Object resolveContextualObject(String key) {
        Map<String, Object> context = getContext();
        return context.get(key);
    }

    @Override
    public String getConversationId() {
        Thread thread = Thread.currentThread();
        return String.valueOf(thread.getId());
    }
}

ThreadLocalScopeDemo

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package springtest.bean.scope;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import springtest.ioc.overview.domain.User;


/**
 * 自定义 Scope {@link ThreadLocalScope} 示例
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class ThreadLocalScopeDemo {

    @Bean
    @Scope(ThreadLocalScope.SCOPE_NAME)
    public User user() {
        return createUser();
    }

    private static User createUser() {
        User user = new User();
        user.setId(System.nanoTime());
        return user;
    }

    public static void main(String[] args) {

        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类) -> Spring Bean
        applicationContext.register(ThreadLocalScopeDemo.class);

        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            // 注册自定义 scope
            beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
        });

        // 启动 Spring 应用上下文
        applicationContext.refresh();

        scopedBeansByLookup(applicationContext);

        // 关闭 Spring 应用上下文
        applicationContext.close();
    }

    private static void scopedBeansByLookup(AnnotationConfigApplicationContext applicationContext) {

        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(() -> {
                // user 是共享 Bean 对象
                User user = applicationContext.getBean("user", User.class);
                System.out.printf("[Thread id :%d] user = %s%n", Thread.currentThread().getId(), user);
            });

            // 启动线程
            thread.start();
            // 强制线程执行完成
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static void scopedBeansByInjection(AnnotationConfigApplicationContext applicationContext) {
    }
}

总结

获取bean对象的方法有三种:
1、在配置文件中定义bean对象,在代码中通过名称、类型和注解查询等方式获取bean对象;
2、在代码中通过BeanDefinition来定义bean对象,并通过查询类型的方式获取bean对象;
3、在代码中创建配置类(相当于定义Bean),在代码中通过名称、类型和注解查询等方式获取bean对象;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值