spring-bean 组件是 IoC 的核心,咱们能够经过BeanFactory
来获取所需的对象,对象的实例化、属性装配和初始化均可以交给 spring 来管理。html
针对 spring-bean 组件,我计划分红两篇博客来说解。本文会详细介绍这个组件,包括如下内容。下一篇再具体分析它的源码。java
正文开始前,先介绍下示例代码使用的环境等。git
JDK:1.8.0_231github
maven:3.6.1spring
IDE:Spring Tool Suites4 for Eclipse 4.12api
Spring:5.2.6.RELEASEmaven
除了引入 spring,这里还额外引入了日志和单元测试。ide
<properties> <spring.version>5.2.6.RELEASE</spring.version> </properties> <dependencies> <!-- spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- logback --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.28</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> <type>jar</type> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> <type>jar</type> </dependency> </dependencies>
在 spring-bean 组件的设计中,这三个词完整、有序地描述了生成一个新对象的整个流程,是很是重要的理论基础。它们的具体含义以下:post
下面使用一段代码来简单演示下这个流程。单元测试
public class UserService implements IUserService { private UserDao userDao; public UserService() { super(); System.err.println("UserService构造方法被调用"); System.err.println(" ||"); System.err.println(" \\/"); } public void init() { System.err.println("UserService的init方法被调用"); System.err.println(" ||"); System.err.println(" \\/"); } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { System.err.println("UserService的属性装配中"); System.err.println(" ||"); System.err.println(" \\/"); this.userDao = userDao; } }
若是咱们将这个 bean 交给 spring 管理,获取 bean 时会在控制台打印如下内容:
按照官方的说法, bean 是一个由 Spring IoC 容器实例化、组装和管理的对象。我认为,这种表述是错误的,经过registerSingleton
方式注册的 bean,它就不是由 Spring IoC 容器实例化、组装,因此,更准确的表述应该是这样:
对象的实例,或者它的描述对象被注册到了 Spring IoC 容器,而且经过 Spring IoC 容器来获取获得的对象,就是 bean。
举个例子,使用了 Spring 的项目中, Controller 对象、Service 对象、DAO 对象等都属于 bean。
至于什么是 IoC 容器,在 spring-bean 组件中,我认为,beanFactory 就属于 IoC 容器。
从客户端来看,一个完整的 beanFactory 工厂通常包含如下功能:
AliasRegistry
接口。SingletonBeanRegistry
接口。BeanDefinition
对象。对应下图的BeanDefinitionRegistry
接口。BeanFactory
接口。在 spring-bean 组件中,DefaultListableBeanFactory
就是一个完整的 beanFactory 工厂,也能够说是一个 IoC 容器。接下来的例子将直接使用它来做为 beanFactory。
至于其余的接口,这里也补充说明下。HierarchicalBeanFactory
用于提供父子工厂的支持,ConfigurableBeanFactory
用于提供配置 beanFactory 的支持,ListableBeanFactory
用于提供批量获取 bean 的支持(不包含父工厂的 bean),AutowireCapableBeanFactory
用于提供实例化、属性装配、初始化等一系列管理 bean 生命周期的支持。
beanDefinaition 是一个描述对象,用来描述 bean 的实例化、初始化等信息。
在 spring-bean 组件中,beanDefinaition主要包含如下四种:
RootBeanDefinition
:beanFactory 中最终用于 createBean 的 beanDefinaition,不容许添加 parentName。在 BeanFactory 中如下三种实现类都会被包装成RootBeanDefinition
用于 createBean。ChildBeanDefinition
:必须设置 parentName 的 beanDefinaition。当某个 Bean 的描述对象和另一个的差很少时,咱们能够直接定义一个ChildBeanDefinition
,并设置它的 parentName 为另一个的 beanName,这样就不用从新设置一份。GenericBeanDefinition
:通用的 beanDefinaition,能够设置 parentName,也能够不用设置。AnnotatedGenericBeanDefinition
:在GenericBeanDefinition
基础上增长暴露注解数据的方法。spring-bean 组件提供了BeanDefinitionBuilder
用于建立 beanDefinaition,下面的例子会频繁使用到。
下面经过一个入门例子来介绍注册和获取 bean 的过程。
@Test public void testBase() { // 建立BeanFactory对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 建立BeanDefinition对象 BeanDefinition rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserService.class).getBeanDefinition(); // 注册Bean beanFactory.registerBeanDefinition("userService", rootBeanDefinition); // 获取Bean IUserService userService = (IUserService)beanFactory.getBean("userService"); System.err.println(userService.get("userId")); }
beanFactory 除了支持注册 beanDefinition,还容许直接注册 bean 实例,以下。
@Test public void testRegisterWays() { // 建立BeanFactory对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 注册Bean-- BeanDefinition方式 BeanDefinition rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserService.class).getBeanDefinition(); beanFactory.registerBeanDefinition("userService", rootBeanDefinition); // 注册Bean-- Bean实例方式 beanFactory.registerSingleton("userService2", new UserService()); // 获取Bean IUserService userService = (IUserService)beanFactory.getBean("userService"); System.err.println(userService.get("userId")); IUserService userService2 = (IUserService)beanFactory.getBean("userService2"); System.err.println(userService2.get("userId")); }
固然,这种方式仅支持单例 bean 的注册,多例的就没办法了。
beanFactory 提供了多种方式来获取 bean 实例,以下。若是同时使用 beanName 和 beanType,获取到指定 beanName 的 bean 后会进行类型检查和类型类型,若是都不经过,将会报错。
@Test public void testGetBeanWays() { // 建立BeanFactory对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 建立BeanDefinition对象 BeanDefinition rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserService.class).getBeanDefinition(); // 注册Bean beanFactory.registerBeanDefinition("userService", rootBeanDefinition); // 获取Bean--经过BeanName IUserService userService = (IUserService)beanFactory.getBean("userService"); System.err.println(userService.get("userId")); // 获取Bean--经过BeanType IUserService userService2 = beanFactory.getBean(IUserService.class); System.err.println(userService2.get("userId")); // 获取Bean--经过BeanName+BeanType的方式 IUserService userService3 = beanFactory.getBean("userService", IUserService.class); System.err.println(userService3.get("userId")); }
另外,经过 beanName 获取 bean,这个 beanName 包含如下三种形式:
FactoryBean
,不会返回FactoryBean
的实例,而是会返回FactoryBean.getObject
方法的返回结果。FactoryBean
的实例,形式为:一个或多个& + factorybeanName。DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 注册Bean--注册的是一个 FactoryBean UserServiceFactoryBean userServiceFactoryBean = new UserServiceFactoryBean(); beanFactory.registerSingleton("userServiceFactoryBean", userServiceFactoryBean); // 注册BeanName的别名 beanFactory.registerAlias("userServiceFactoryBean", "userServiceAlias01"); // 经过BeanName获取 assertEquals(userServiceFactoryBean.getObject(), beanFactory.getBean("userServiceFactoryBean")); // 经过别名获取 assertEquals(userServiceFactoryBean.getObject(), beanFactory.getBean("userServiceAlias01")); // 经过&+FactoryBeanName的方式 assertEquals(userServiceFactoryBean, beanFactory.getBean("&UserServiceFactoryBean"));
经过 beanType 的方式获取 bean,若是存在多个同类型的 bean且没法肯定最优先的那一个,就会报错。
@Test public void testPrimary() { // 建立BeanFactory对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 建立BeanDefinition对象 BeanDefinition rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); BeanDefinition rootBeanDefinition2 = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); // 注册Bean beanFactory.registerBeanDefinition("UserRegisterBeanDefinition", rootBeanDefinition); beanFactory.registerBeanDefinition("UserRegisterBeanDefinition2", rootBeanDefinition2); beanFactory.registerSingleton("UserRegisterSingleton", new User("zzs002", 19)); beanFactory.registerSingleton("UserRegisterSingleton2", new User("zzs002", 18)); // 获取Bean--经过BeanType User user = beanFactory.getBean(User.class); System.err.println(user); }
运行以上方法,将出现 NoUniqueBeanDefinitionException 的异常。
针对上面的这种问题,能够采起两种解决方案:
BeanDefinition
对象的 isPrimary = true。这种方式不适用于 registerSingleton 的状况。其中,1 方案要优先于 2 方案。
@Test public void testPrimary() { // 建立BeanFactory对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 为BeanFactory设置比较器 beanFactory.setDependencyComparator(new OrderComparator() { @Override public Integer getPriority(Object obj) { return obj.hashCode(); } }); // 建立BeanDefinition对象 BeanDefinition rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); // rootBeanDefinition.setPrimary(true); // 设置BeanDefinition对象为isPrimary BeanDefinition rootBeanDefinition2 = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); // 注册Bean beanFactory.registerBeanDefinition("userRegisterBeanDefinition", rootBeanDefinition); beanFactory.registerBeanDefinition("userRegisterBeanDefinition2", rootBeanDefinition2); beanFactory.registerSingleton("userRegisterSingleton", new User("zzs002", 19)); beanFactory.registerSingleton("userRegisterSingleton2", new User("zzs002", 18)); // 获取Bean--经过BeanType User user = beanFactory.getBean(User.class); System.err.println(user); }
默认状况下,咱们从 beanFactory 获取到的 bean 都是单例的,即同一个对象,实际项目中,有时咱们须要获取到多例的 bean,这个时候就能够经过设置 beanDefinition 的 scope 来处理。以下:
@Test public void testScope() { // 建立BeanFactory对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 注册Bean-- BeanDefinition方式 BeanDefinition rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserService.class).getBeanDefinition(); rootBeanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE); beanFactory.registerBeanDefinition("userService", rootBeanDefinition); // 获取Bean--经过BeanType IUserService userService1 = beanFactory.getBean(IUserService.class); IUserService userService2 = beanFactory.getBean(IUserService.class); assertNotEquals(userService1, userService2); }
当咱们同时使用 beanName + beanType 来获取 bean 时,若是获取到的 bean 不是指定的类型,这时,不会当即报错,beanFactory 会尝试使用TypeConverter
来强制转换。而这个类型转换器咱们能够自定义设置,以下。
@Test public void testTypeConverter() { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 注册类型转换器 beanFactory.setTypeConverter(new TypeConverterSupport() { @SuppressWarnings("unchecked") @Override public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException { // 将User转换为UserVO if(UserVO.class.equals(requiredType) && User.class.isInstance(value)) { User user = (User)value; return (T)new UserVO(user); } return null; } }); BeanDefinition rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); beanFactory.registerBeanDefinition("User", rootBeanDefinition); UserVO bean = beanFactory.getBean("User", UserVO.class); Assert.assertTrue(UserVO.class.isInstance(bean)); }
若是我想在UserService
中注入UserDao
,首先,须要在UserService
中添加定义的 setter/getter 方法,以下:
public class UserService implements IUserService { private UserDao userDao; public void save(User user) { System.err.println("Service save user:" + user); userDao.save(user); } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
在注册 bean 时须要注意,UserDao
的 bean 也须要注册,并且须要更改 userServiceBeanDefinition 的 autowireType 为按 beanType 注入或按 beanName 注入。
@Test public void testPopulate() { // 建立BeanFactory对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 建立BeanDefinition对象 AbstractBeanDefinition userServiceBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserService.class).getBeanDefinition(); // userServiceBeanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); userServiceBeanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME); AbstractBeanDefinition userDaoBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserDao.class).getBeanDefinition(); // 注册Bean beanFactory.registerBeanDefinition("userService", userServiceBeanDefinition); beanFactory.registerBeanDefinition("userDao", userDaoBeanDefinition); // 获取Bean IUserService userService = (IUserService)beanFactory.getBean("userService"); userService.save(null); }
运行以上方法,属性装配正常。
前面讲到,咱们将 bean 的实例化、属性装配和初始化都交给了 spring 处理,然而,有时咱们须要在这些节点对 bean 进行自定义的处理,这时就须要用到 beanPostProcessor。
这里我简单演示下如何添加处理器,以及处理器的执行时机,至于处理器的具体实现,我就很少扩展了。
@Test public void testPostProcessor() { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 添加实例化处理器 beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() { public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { if(UserService.class.equals(beanClass)) { System.err.println("实例化以前的处理。。 --> "); } return null; } @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { if(UserService.class.isInstance(bean)) { System.err.println("实例化以后的处理。。 --> "); } return true; } }); // 添加属性装配处理器 beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() { @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { if(UserService.class.isInstance(bean)) { System.err.println("设置参数前对参数进行调整 --> "); } return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName); } @Override public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { if(UserService.class.isInstance(bean)) { System.err.println("设置参数前对参数进行检查依赖关系 --> "); } return InstantiationAwareBeanPostProcessor.super.postProcessPropertyValues(pvs, pds, bean, beanName); } }); // 添加初始化处理器 beanFactory.addBeanPostProcessor(new BeanPostProcessor() { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(UserService.class.isInstance(bean)) { System.err.println("初始化前,对Bean进行改造。。 --> "); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(UserService.class.isInstance(bean)) { System.err.println("初始化后,对Bean进行改造。。 --> "); } return bean; } }); AbstractBeanDefinition userServiceBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserService.class).getBeanDefinition(); AbstractBeanDefinition userDaoBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(UserDao.class).getBeanDefinition(); userServiceBeanDefinition.setInitMethodName("init"); userServiceBeanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); beanFactory.registerBeanDefinition("userService", userServiceBeanDefinition); beanFactory.registerBeanDefinition("userDao", userDaoBeanDefinition); IUserService userService = (IUserService)beanFactory.getBean("userService"); System.err.println(userService.get("userId")); }
运行以上方法,控制台打印出了整个处理流程。实际开发中,咱们能够经过设置处理器来改变改造生成的 bean 。
以上,基本介绍完 spring-bean 组件的使用,下篇博客再分析源码,若是在分析过程当中发现有其余特性,也会在这篇博客的基础上扩展。
相关源码请移步: spring-beans
本文为原创文章,转载请附上原文出处连接:http://www.javashuo.com/article/p-uegndqxn-br.html