第四章:Spring Bean基础 定义 Spring Bean 什么是 BeanDefinition? BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口,包含:
Bean 的类名
Bean 行为配置元素,如作用域、自动绑定的模式,生命周期回调等
其他 Bean 引用,又可称作合作者(collaborators)或者依赖(dependencies)
配置设置,比如 Bean
BeanDefinition元信息
BeanDefinition 构建 通过 BeanDefinitionBuilder
1 2 3 4 5 6 7 8 9 10 11 public static void createByBeanDefinitionBuilder () { BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class); beanDefinitionBuilder .addPropertyValue("id" ,1L ) .addPropertyValue("name" ,"kesen" ); BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); beanDefinition.setLazyInit(false ); }
通过 AbstractBeanDefinition 以及派生类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void createByAbstractBeanDefinition () { GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition(); genericBeanDefinition.setBeanClass(SuperUser.class); MutablePropertyValues mutablePropertyValues = new MutablePropertyValues(); mutablePropertyValues .add("id" ,1L ) .add("name" ,"kesen" ) .add("address" ,"Chengdu" ); genericBeanDefinition.setPropertyValues(mutablePropertyValues); }
命名 Spring Bean
Bean 的名称 每个 Bean 拥有一个或多个标识符(identifiers),这些标识符在 Bean 所在的容器必须是 唯一的。通常,一个 Bean 仅有一个标识符,如果需要额外的,可考虑使用别名(Alias)来 扩充。
在基于 XML 的配置元信息中,开发人员可用 id 或者 name 属性来规定 Bean 的 标识符。
通 常 Bean 的 标识符由字母组成,允许出现特殊字符。如果要想引入 Bean 的别名的话,可在 name 属性使用半角逗号(“,”)或分号(“;”) 来间隔。 Bean 的 id 或 name 属性并非必须制定,如果留空的话,容器会为 Bean 自动生成一个唯一 的名称。Bean 的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合 Java 的命名约 定
Bean 名称生成器(BeanNameGenerator)
由 Spring Framework 2.0.3 引入,框架內建两种实现: DefaultBeanNameGenerator:默认通用 BeanNameGenerator 实现
AnnotationBeanNameGenerator:基于注解扫描的 BeanNameGenerator 实现,起始于 Spring Framework 2.5,关联的官方文档:
Spring Bean 的别名 Bean 别名(Alias)的价值
复用现有的 BeanDefinition
更具有场景化的命名方法,比如:
1 2 3 4 5 6 7 8 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:META-INF/bean-definition-context.xml" ); User user = context.getBean("user" , User.class); User normalUser = context.getBean("commonUser" , User.class); System.out.println(user == normalUser);
注册 Spring Bean BeanDefinition 注册 XML 配置元信息
Java 注解配置元信息
@Bean
@Component + @ComponentScan
@Import
Java API 配置元信息
命名方式:BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
非命名方式: BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,BeanDefinitionRegistry)
配置类方式:AnnotatedBeanDefinitionReader#register(Class…)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @Import(AnnotationBeanDefinitionDemo.Config.class) public class AnnotationBeanDefinitionDemo { public static void main (String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(Config.class); context.refresh(); registerUserBeanDefinition(context, "specialUser" ); registerUserBeanDefinition(context); System.out.println("Config Beans:" + context.getBeansOfType(Config.class)); System.out.println("User Beans:" + context.getBeansOfType(User.class)); String[] users = context.getAliases("user" ); System.out.println(Arrays.toString(users)); context.close(); } private static void registerUserBeanDefinition (BeanDefinitionRegistry registry) { registerUserBeanDefinition(registry, null ); } private static void registerUserBeanDefinition (BeanDefinitionRegistry registry, String beanName) { BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class); beanDefinitionBuilder .addPropertyValue("id" , 2 ) .addPropertyValue("name" , "Tom" ); AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); if (StringUtils.hasText(beanName)) { registry.registerBeanDefinition(beanName, beanDefinition); } else { BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry); } } @Component public static class Config { @Bean({"user", "cruise"}) public User user () { User user = new User(); user.setId(1L ); user.setName("Cruise" ); return user; } }
外部单例对象注册
SingletonBeanRegistry#registerSingleton
1 2 3 4 5 6 7 8 9 10 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.refresh(); ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("admin" ,new User()); User user = context.getBean("user" , User.class); System.out.println(user); context.close();
实例化Spring Bean
静态工厂方法 1 2 3 <bean id ="user-by-static-method" class ="com.cruise.thinking.in.spring.ioc.container.overview.domain.User" factory-method ="createUser" />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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 + '\'' + '}' ; } public static User createUser () { User user = new User(); user.setId(1L ); user.setName("Cruise" ); return user; } }
Bean工厂 1 2 3 4 <bean id ="user-by-instance-method" factory-bean ="userFactory" factory-method ="createUser" /> <bean id ="userFactory" class ="com.cruise.thinking.in.spring.bean.definition.factory.DefaultUserFactory" />
抽象工厂
1 2 3 4 5 public interface UserFactory { default User createUser () { return User.createUser(); } }
工厂实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class DefaultUserFactory implements UserFactory , InitializingBean , DisposableBean { @PostConstruct public void postConstruct () { System.out.println("PostConstruct" ); } public void myInit () { System.out.println("myInit" ); } @Override public void afterPropertiesSet () throws Exception { System.out.println("InitializingBean#afterPropertiesSet" ); } @PreDestroy public void preDestroy () { System.out.println("PreDestroy" ); } @Override public void destroy () throws Exception { System.out.println("DisposableBean#destroy" ); } public void myDestroy () { System.out.println("myDestroy" ); } @Override protected void finalize () throws Throwable { System.out.println("finalize" ); } }
FactoryBean 1 2 <bean id ="user-by-factory-bean" class ="com.cruise.thinking.in.spring.bean.definition.factory.UserFactoryBean" />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class UserFactoryBean implements FactoryBean <User > { @Override public User getObject () throws Exception { return User.createUser(); } @Override public Class<?> getObjectType() { return User.class; } @Override public boolean isSingleton () { return false ; } }
初始化Spring Bean
1 2 3 4 5 6 7 8 9 10 @Bean(initMethod = "myInit") public UserFactory userFactory () { return new DefaultUserFactory(); } AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Student.class) .setInitMethodName("initStudent" ).getBeanDefinition(); context.registerBeanDefinition("student" ,beanDefinition);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class DefaultUserFactory implements UserFactory , InitializingBean , DisposableBean { @PostConstruct public void postConstruct () { System.out.println("PostConstruct" ); } public void myInit () { System.out.println("myInit" ); } @Override public void afterPropertiesSet () throws Exception { System.out.println("InitializingBean#afterPropertiesSet" ); } @PreDestroy public void preDestroy () { System.out.println("PreDestroy" ); } @Override public void destroy () throws Exception { System.out.println("DisposableBean#destroy" ); } public void myDestroy () { System.out.println("myDestroy" ); } @Override protected void finalize () throws Throwable { System.out.println("finalize" ); }
顺序:
PostConstruct InitializingBean#afterPropertiesSet myIni
延迟初始化 Spring Bean Bean 延迟初始化(Lazy Initialization)
XML 配置:<bean lazy-init=”true” … />
Java 注解:@Lazy(true)
思考:当某个 Bean 定义为延迟初始化,那么,Spring 容器返回的对象与非延迟的对象存在怎样的差异?
生命周期
销毁 Spring Bean Bean 销毁(Destroy)
XML 配置: <bean destroy=”destroy” … />
Java 注解:@Bean(destroy=”destroy”)
Java API:AbstractBeanDefinition#setDestroyMethodName(String)
思考:假设以上三种方式均在同一 Bean 中定义,那么这些方法的执行顺序是怎样
顺序
PreDestroy DisposableBean#destroy myDestroy
1 2 3 System.out.println("Spring上下文准备关闭" ); context.close(); System.out.println("Spring上下文已经关闭" );
1 2 3 4 5 Spring上下文准备关闭 PreDestroy DisposableBean#destroy myDestroy Spring上下文已经关闭
垃圾回收 Spring Bean Bean 垃圾回收(GC)
关闭 Spring 容器(应用上下文)
执行 GC
Spring Bean 覆盖的 finalize() 方法被回
1 2 3 4 5 6 7 8 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanDestroyDemo.class); System.out.println(context.getBean(UserFactory.class)); context.close(); System.out.println("Spring上下文关闭了" ); Thread.sleep(2000 ); System.gc();