Spring编程思想:一. Spring Bean基础

1. 定义Spring Bean

BeanDefinition用来描述Spring中的Bean对象,包含:

  • Bean的类名
  • Bean配置元信息:作用域、自动绑定的模式、生命周期回调
  • 其他Bean引用,或依赖
  • Bean属性

2. BeanDefinition 元信息

2.1 概述

属性说明
classBean 全类名,必须是具体类,不能用抽象类或接口
NameBean 的名称或ID(Bean的识别符)
ScopeBean 的作用域(如:singletonprototype等)
Constructor argumentsBean 构造器参数(用于依赖注入)
PropertiesBean 属性设置(用于依赖注入)
Autowiring modeBean 自动绑定模式(如:byName,byType等等)
Lazy initialization modeBean 延迟初始化模式(延迟和非延迟)
Initialization methodBean 初始化回调方法名称
Destruction methodBean 销毁回调方法名称

2.2 BeanDefinition构建

有以下2种方式可以构建BeanDefinition:

  • 通过 BeanDefinitionBuilder
  • 通过 AbstractBeanDefinition 以及派生类
public class BeanDefinitionCreationDemo {
    public static void main(String[] args) {
    }

    /**
     * 通过 BeanDefinitionBuilder 来构建BeanDefinition
     */
    private void createBeanDefinitionByBeanDefinitionBuilder() {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        // 通过属性设置
        beanDefinitionBuilder.addPropertyValue("id", 1);
        beanDefinitionBuilder.addPropertyValue("name", "张三");
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        // BeanDefinition 并非 Bean 的最终态,可以自定义修改:比如 beanDefinition.setXXX()
    }

    /**
     * 通过 AbstractBeanDefinition 来创建BeanDefinition
     */
    private void createBeanDefinitionByAbstractBeanDefinition() {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        // 设置Bean类型
        beanDefinition.setBeanClass(User.class);
        // 通过 MutablePropertyValues 批量操作属性
        MutablePropertyValues values = new MutablePropertyValues();
        values.add("id", 1)
                .add("name", "李四");
        beanDefinition.setPropertyValues(values);
    }
}

3. 命名Spring Bean

每个Bean拥有一个或多个标识符,这些标识符在Bean所在的容器中必须是唯一的。通常,一个Bean仅有一个标识符,可以使用别名来扩充。

可以使用id或者name来规定Bean的标识符,如果想引入别名,可以在name属性中使用 “,” 或 “;” 来间隔。

如果不指定id或者name属性,则可以由 DefaultBeanNameGenerator 来生成Bean的名称。

3.1 Bean的别名

Bean别名的价值:

  • 复用现有的BeanDefinition
  • 更具有场景化的命名方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 如果只设置id,则id就是bean的标识符;如果只设置name,则name就是bean的标识符 -->
    <!-- 如果既设置了id,也设置了name,则id是标识符,name是别名 -->
    <!-- name可以设置多个,比如 name="a,b,c",但是不管id还是name,在容器中必须唯一 -->
    <bean id="user" class="com.hermione.entity.User">
        <property name="id" value="1"/>
        <property name="name" value="hermione"/>
    </bean>

    <!-- 必须加上primary,这样在获取单个Bean的时候不会报错(因为容器中有两个User类型的Bean) -->
    <bean id="superUser" class="com.hermione.entity.SuperUser" parent="user" primary="true">
        <property name="address" value="上海"/>
    </bean>

    <!-- 给Spring 容器中的 user Bean 建立一个别名 common-user -->
    <alias name="user" alias="common-user"/>

</beans>
public class BeanAliasDemo {
    public static void main(String[] args) {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definition-context.xml");
        User user1 = beanFactory.getBean("common-user", User.class);
        User user2 = beanFactory.getBean("user", User.class);
        System.out.println("common-user " + (user1 == user2 ? "==" : "!=") + " user");       // common-user == user
    }
}

4. 注册Spring Bean

BeanDefinition 的注册:

  • XML配置元信息:

    • <bean name="xx" .. />
  • Java注解配置元信息

    • @Bean
    • @Component
    • @Import
  • Java API配置元信息

    • 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String , BeanDefinition)

    • 非命名方式:BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition, BeanDefinitionRegistry)

      本质上也是调用了 BeanDefinitionRegistry#registerBeanDefinition(String , BeanDefinition)

    • 配置类方式:AnnotatedBeanDefinitionReader#register(Class)

@Import(AnnotationBeanDefinitionDemo.Config.class)                  // 把 Config 注册为Spring Bean
public class AnnotationBeanDefinitionDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        applicationContext.register(AnnotationBeanDefinitionDemo.class);          // 把 AnnotationBeanDefinitionDemo 注册为Spring Bean

        applicationContext.refresh();

        Map<String, AnnotationBeanDefinitionDemo> map1 = applicationContext.getBeansOfType(AnnotationBeanDefinitionDemo.class);
        System.out.println(map1);                   // {annotationBeanDefinitionDemo=com.hermione.bean.register.AnnotationBeanDefinitionDemo@36b4cef0}

        Map<String, Config> map2 = applicationContext.getBeansOfType(Config.class);
        System.out.println(map2);                   // {com.hermione.bean.register.AnnotationBeanDefinitionDemo$Config=com.hermione.bean.register.AnnotationBeanDefinitionDemo$Config@fad74ee}

        Map<String, User> map3 = applicationContext.getBeansOfType(User.class);
        System.out.println(map3);                   // {user=com.hermione.entity.User@1a1d6a08}

        Map<String, Student> map4 = applicationContext.getBeansOfType(Student.class);
        System.out.println(map4);                   // {}

        Map<String, Config.Teacher> map5 = applicationContext.getBeansOfType(Config.Teacher.class);
        System.out.println(map5);                   // {}
    }

    public static class Config {
        /**
         * 1. 通过 @Bean 方式定义
         */
        @Bean(name = {"user", "hermione"})
        public User user() {
            User user = new User();
            user.setId(1);
            user.setName("hermione");
            return user;
        }

        @Component
        public static class Teacher {
            private String name = "teacher";
        }
    }

    @Component
    public static class Student {
        private String name = "student";
    }
}

5. 实例化Spring Bean

Bean实例化的方式:

  • 常规方式:

    • 通过构造器(配置元信息:XML、Java注解和Java API)

    • 通过静态工厂方法(配置元信息:XML和Java API)

    • 通过Bean工厂方法(配置元信息:XML和Java API)

    • 通过FactoryBean(配置元信息:XML、Java注解和Java API)

      FactoryBean 主要使用在对象初始化较复杂的场景中

  • 特殊方式:

    • 通过 ServiceLoaderFactoryBean(配置元信息:XML、Java注解和Java API)

      • ServiceLoader 是JDK1.6提供的一种IoC机制,默认会去加载classpath下的 META-INF/services 目录中符合格式的文件,文件名是接口的全路径,文件内容是接口的所有实现类(用 “,” 间隔),ServiceLoader 可以获取文件中列举的接口的所有实现类

      • META-INF/services 这个路径是在 ServiceLoader 类中定义的

        image-20201107090727315

    • 通过 AutowireCapableBeanFactory#createBean(Class, int, boolean)

    • 通过 BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)

1. 常规方式

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

        user = beanFactory.getBean("user-by-instance-method", User.class);
        System.out.println(user);

        user = beanFactory.getBean("user-by-factory-bean", User.class);
        System.out.println(user);

        beanFactory.close();
    }
}

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

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

public class UserFactory {
    public User createUser() {
        return User.createUser();
    }
}

public class User {
    private int id;
    private String name;

    public static User createUser() {
        User user = new User();
        user.setId(2);
        user.setName("hermione");
        return user;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 通过静态工厂的方式实例化Bean -->
    <bean id="user-by-static-method" class="com.hermione.entity.User" factory-method="createUser" />

    <!-- 实例方法实例化Bean,一般很少这样用 -->
    <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser" />
    <bean id="userFactory" class="com.hermione.bean.instantiation.DefaultUserFactory" />

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

</beans>

2. 特殊方式

public class SpecialBeanInstantiationDemo {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
            						"classpath:META-INF/special-bean-instantiation-context.xml");
        // 通过ApplicationContext 获取 AutowireCapableBeanFactory
        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
        ServiceLoader<UserFactory> serviceLoader = beanFactory.getBean("user-factory-service-loader", ServiceLoader.class);
        display(serviceLoader);
		
        // 特殊方式第二种
        User user = beanFactory.createBean(User.class);
        System.out.println(user);                           // User(id=0, name=null)
    }

    private static void display(ServiceLoader<UserFactory> serviceLoader) {
        Iterator<UserFactory> iterator = serviceLoader.iterator();
        while (iterator.hasNext()) {
            UserFactory userFactory = iterator.next();
            System.out.println(userFactory.createUser());
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 这个 ServiceLoaderFactoryBean 本质是一个FactoryBean,所以getBean的时候返回的就是 getObject() 中 返回的对象,也就是 ServiceLoader -->
    <!-- 这里可以对比下 ServiceLoaderFactoryBean 和 ServiceFactoryBean: -->
    <!--
        public class ServiceFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {
                @Override
                protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
                    Iterator<?> it = serviceLoader.iterator();
                    if (!it.hasNext()) {
                        throw new IllegalStateException("ServiceLoader could not find service.. ");
                    }
                    return it.next();
                }
        }
        
        public class ServiceLoaderFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {
            @Override
            protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
                return serviceLoader;
            }
        }
        
        对比这两个类发现:
            ServiceLoaderFactoryBean#getObject() 返回的是 ServiceLoader 的对象,
            ServiceFactoryBean#getObject() 返回 ServiceLoader 中加载的接口的实现类(只有第一个)
    -->
    <bean id="user-factory-service-loader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
        <property name="serviceType" value="com.hermione.bean.instantiation.UserFactory"/>
    </bean>


6. 初始化Spring Bean

Bean初始化的方式:

  • @PostConstruct 标注方法
  • 实现 InitializingBean 接口的 afterPropertiesSet() 方法
  • 自定义初始化方法:下面这三种方式本质是相同的,都是调用了 setInitMethodName() 方法
    • XML配置:<eabn init-methodd="init" ../>
    • Java注解:@Bean(initMethod = "init")
    • Java API:AbstractBeanDefinition#setInitMethodName(String)
public class BeanInitializationDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(BeanInitializationDemo.class);
        applicationContext.refresh();

        applicationContext.getBean(UserFactory.class);

        applicationContext.close();
    }

    @Lazy					// 延迟初始化
    @Bean(initMethod = "initUserFactory")
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}
public class DefaultUserFactory implements UserFactory, InitializingBean {

    // 1. 基于 @PostConstruct 注解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct");
    }

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

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }
}

执行顺序是:@PostConstruct -> InitializingBean#afterPropertiesSet() -> 自定义初始化方法。

7. 延迟初始化Spring Bean

Bean延迟初始化的方式:

  • XML配置:<bean lazy-init = "true" .. />
  • Java注解:@Lazy(true)

非延迟加载是在Spring应用上下文启动完成(refresh())后,被初始化

延迟加载是按需初始化,只有在使用到这个Bean的时候才会初始化。

public abstract class AbstractApplicationContext {
    @Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.  在这里会初始化所有非懒加载的单体Bean
				finishBeanFactoryInitialization(beanFactory);
			
				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				// ..
			}

			finally {
				// ..
			}
		}
	}
}

8. 销毁Spring Bean

Bean的销毁方式:

  • @PreDestory 注解方法
  • 实现 DisposableBean 接口的 destroy() 方法
  • 自定义销毁方法:
    • XML配置:<bean destroy = "destroy" ../>
    • Java注解:@Bean(destroy = "destroy")
    • Java API:AbstractBeanDefinition#setDestroyMethodName(String)

执行顺序和初始化方法相同:@PreDestory -> DisposableBean#destroy() -> 自定义销毁方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值