我之前出过一个系列介绍的是spring的源码的系列,但是由于当时个人的水平有限,有些地方介绍的也是模棱两可的,打算重启这块内容,上次只是介绍其中的一部分,例如国际化,事件等等这块的源码都没有介绍,还有事务这块内容。spring现在也不单单是一个简简单单的只是spring framework,它有很广的生态,但是这些所有的生态都是基于spring framework来的,今天我们就来全览一下spring的内容,同时介绍一下IOC,以及spring是如何实现IOC的,还有就是spring Bean 的一些基础的知识。
In software engineering, inversion of control (IoC) is a programming principle. IoC inverts the flow of control as compared to traditional control flow. In IoC, custom-written portions of a computer program receive the flow of control from a generic framework. A software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls into the custom, or task-specific, code.
在软件工程中,控制反转(IOC)是编程原理。与传统的对照流相比,IOC将控制流动。在IOC中,计算机程序的定制写入部分从通用框架接收控制流。与传统的程序编程相比,具有此设计的软件体系结构将控制权反转:在传统编程中,将程序的目的表达为可重复使用的库以处理通用任务,但通过控制反转,它是框架该调用到自定义或特定任务的代码中。
Implementation techniques(实现技术) 小节的定义:
《Expert One-on-One™ J2EE™ Development without EJB™》 提到的主要实现策略:IoC is a broad concept that can be implemented in different ways. There are two main types:(IO是一个广泛的概念,可以以不同的方式实现。主要有两种类型)
在 Overview 小节中提到:
通用职责
生命周期管理
配置
主要实现
Java EE
开源
这儿我们可以看下Java Beans的代码。具体的如下:
package org.geekbang.ioc.java.beans;
/**
* 描述人的POJO
*
* setter / getter方法
* 可写方法(writable) / 可读方法(readable)
*/
public class Person {
String name;
Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
package org.geekbang.ioc.java.beans;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyEditorSupport;
import java.util.stream.Stream;
/**
* {@link BeanInfo} 实例
*/
public class BeanInfoDemo {
public static void main(String[] args) throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);
Stream.of(beanInfo.getPropertyDescriptors())
.forEach(propertyDescriptor -> {
// PropertyDescriptor 允许添加属性编辑器 PropertyEditor
// GUI -> text(String) -> PropertyType
// name -> String
// age -> Integer
Class<?> propertyType = propertyDescriptor.getPropertyType();
String propertyName = propertyDescriptor.getName();
if ("age".equals(propertyName)) { // 为"age" 属性/字段 添加PropertyEditor
// String -> Integer
//Integer.valueOf()
propertyDescriptor.setPropertyEditorClass(StringToIntegerPropertyEditor.class);
//propertyDescriptor.createPropertyEditor()
}
});
}
static class StringToIntegerPropertyEditor extends PropertyEditorSupport {
public void setAsText(String text) throws java.lang.IllegalArgumentException {
Integer value = Integer.valueOf(text);
setValue(value);
}
}
}
上面简单的介绍了JavaBean的一些简单的API。Spring中也有简单的应用。
Java Beans 作为 IoC 容器
特性
规范
《Expert One-on-One™ J2EE™ Development without EJB™》 认为轻量级容器的特征:
Expert One-on-One™ J2EE™ Development without EJB™》 认为轻量级容器的好处:
Spring Framework 对构造器注入与 Setter 的论点:
《Expert One-on-One™ J2EE™ Development without EJB™》 认为 Setter 注入的优点:
Advantages of Setter Injection include:(setter注入的优点包括:)
《Expert One-on-One™ J2EE™ Development without EJB™》 认为 Setter 注入的缺点:
Disadvantages include:(缺点包括)
《Expert One-on-One™ J2EE™ Development without EJB™》 认为构造器注入的优点:
Advantages of Constructor Injection include:(构造函数注入的优点包括)
《Expert One-on-One™ J2EE™ Development without EJB™》 认为构造器注入的缺点:
Disadvantages include:(缺点包括)
根据 Bean 名称查找
根据 Bean 类型查找
根据 Java 注解查找
具体的几种查找的代码如下:
package org.learn.spring.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 + '\'' +
'}';
}
}
package org.learn.spring.ioc.overview.domain;
import org.learn.spring.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();
}
}
package org.learn.spring.ioc.overview.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Super {
}
<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 id="user" class="org.learn.spring.ioc.overview.domain.User">
<property name="id" value="1"/>
<property name="name" value="胡桃"/>
bean>
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
bean>
<bean id="superUser" class="org.learn.spring.ioc.overview.domain.SuperUser" parent="user" primary="true">
<property name="address" value="璃月"/>
bean>
beans>
package org.learn.spring.ioc.overview.dependency.lookup;
import org.learn.spring.ioc.overview.annotation.Super;
import org.learn.spring.ioc.overview.domain.SuperUser;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Map;
// 依赖查找的示例
public class DependencyLookupDemo {
public static void main(String[] args) {
// 配置XML 配置文件
// 启动spring的应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/dependency-lookup-context.xml");
// 1.按照名称查找
lookupInRealTime(beanFactory);
lookupInLazy(beanFactory);
// 2.按照类型查找
lookupByType(beanFactory);
lookupCollectionByType(beanFactory);
// 3.按照类型和名称查找
lookupByNameAndType(beanFactory);
// 4.通过注解查找对象
lookupCollectionByAnnotation(beanFactory);
}
// 实时查找
private static void lookupInRealTime(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("实时查找:" + user);
}
// 延时查找
private static void lookupInLazy(BeanFactory beanFactory) {
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
User user = objectFactory.getObject();
System.out.println("延时查找:" + user);
}
// 按照类型查找
private static void lookupByType(BeanFactory beanFactory) {
User user = beanFactory.getBean(User.class);
System.out.println("按照类型查找单一对象:" + user);
}
// 按照类型查找集合
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("按照类型查找到的所有的 User 集合对象:" + users);
}
}
// 按照类型和名称
private static void lookupByNameAndType(BeanFactory beanFactory) {
User user = beanFactory.getBean("user", User.class);
System.out.println("按照类型和名称查找:" + user);
}
// 按照注解查找集合对象
private static void lookupCollectionByAnnotation(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("按照注解查找到的所有的标注@SuperUser User 集合对象:" + users);
}
}
}
根据 Bean 名称注入
根据 Bean 类型注入
注入容器內建 Bean 对象
注入非 Bean 对象
注入类型
具体的几种依赖注入的代码如下:
package org.learn.spring.ioc.overview.repository;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationContext;
import java.util.Collection;
// 用户的信息仓库
public class UserRepository {
private Collection<User> users; // 自定义Bean
private BeanFactory beanFactory; // 内建非Bean对象(依赖)
private ObjectFactory<User> userObjectFactory;
private ObjectFactory<ApplicationContext> objectFactory;
public Collection<User> getUsers() {
return users;
}
public void setUsers(Collection<User> users) {
this.users = users;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public ObjectFactory<User> getUserObjectFactory() {
return userObjectFactory;
}
public void setUserObjectFactory(ObjectFactory<User> userObjectFactory) {
this.userObjectFactory = userObjectFactory;
}
public ObjectFactory<ApplicationContext> getObjectFactory() {
return objectFactory;
}
public void setObjectFactory(ObjectFactory<ApplicationContext> objectFactory) {
this.objectFactory = objectFactory;
}
}
<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">
<import resource="dependency-lookup-context.xml"/>
<bean id="userRepository" class="org.learn.spring.ioc.overview.repository.UserRepository" autowire="byType"/>
beans>
package org.learn.spring.ioc.overview.dependency.injection;
import org.learn.spring.ioc.overview.domain.User;
import org.learn.spring.ioc.overview.repository.UserRepository;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// 依赖注入的示例
public class DependencyInjectionDemo {
public static void main(String[] args) {
// 配置XML 配置文件
// 启动spring的应用上下文
// 根据名称进行注入autowire byName 根据类型进行注入autowire byType 都是在xml的配置文件中配置好了
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/dependency-injection-context.xml");
UserRepository userRepository = (UserRepository) beanFactory.getBean("userRepository");
System.out.println(userRepository.getUsers());
// 注入容器内建的依赖, 非 Bean 对象 这儿是依赖注入,
System.out.println(userRepository.getBeanFactory());
System.out.println(beanFactory == userRepository.getBeanFactory());
// 这行代码直接报错,这儿是依赖查找 这两段的代码可以知道依赖查找和依赖注入 的依赖的来源是不一样的
//System.out.println(beanFactory.getBean(BeanFactory.class));
// 延时注入 上面的都是实时注入
ObjectFactory<User> userObjectFactory = userRepository.getUserObjectFactory();
System.out.println(userObjectFactory.getObject());
ObjectFactory<ApplicationContext> objectFactory = userRepository.getObjectFactory();
System.out.println(objectFactory.getObject());
System.out.println(objectFactory.getObject() == beanFactory);
}
}
我们借用一下前面的代码,具体的代码如下
package org.learn.spring.ioc.overview.dependency.injection;
import org.learn.spring.ioc.overview.domain.User;
import org.learn.spring.ioc.overview.repository.UserRepository;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// 依赖来源的示例
public class DependencyInjectionDemo {
public static void main(String[] args) {
// 配置XML 配置文件
// 启动spring的应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/dependency-injection-context.xml");
UserRepository userRepository = (UserRepository) beanFactory.getBean("userRepository");
// 来源一:自定义的Bean
System.out.println(userRepository.getUsers());
// 来源二:容器的内建依赖
System.out.println(userRepository.getBeanFactory());
// 来源三:容器内建的Bean
Environment environment = beanFactory.getBean(Environment.class);
System.out.println(environment);
}
}
Bean 定义配置
IoC 容器配置
外部化属性配置
BeanFactory 和 ApplicationContext 谁才是 Spring IoC 容器?
ApplicationContext 除了 IoC 容器角色, 还有提供:
BeanFactory 是 Spring 底层 IoC 容器 ApplicationContext 是具备应用特性的 BeanFactory 超集
再来看下如下的代码,简单的对比一下BeanFactory 和 ApplicationContext:
package org.learn.spring.ioc.overview.container;
import org.learn.spring.ioc.overview.domain.User;
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.beans.factory.xml.XmlReaderContext;
import java.util.Map;
// BeanFactory作为IOC容器示例
public class BeanFactoryAsIoCContainerDemo {
public static void main(String[] args) {
// 创建BeanFactory容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// XML 配置文件的路径
String location = "classpath:META-INF/dependency-lookup-context.xml";
// 加载配置
int beanDefinitionsCount = reader.loadBeanDefinitions(location);
System.out.println("Bean 定义加载的数量:"+beanDefinitionsCount);
// 依赖查找集合对象
lookupCollectionByType(beanFactory);
}
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("按照类型查找到的所有的 User 集合对象:" + users);
}
}
}
package org.learn.spring.ioc.overview.container;
import org.learn.spring.ioc.overview.domain.User;
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 java.util.Map;
// AnnotationApplicationContext作为IOC容器示例
public class AnnotationApplicationContextAsIoCContainerDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类AnnotationApplicationContextAsIoCContainerDemo 作为配置类(configuration class)
applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
// 启动应用上下文
applicationContext.refresh();
// 依赖查找集合对象
lookupCollectionByType(applicationContext);
}
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("按照类型查找到的所有的 User 集合对象:" + users);
}
}
@Bean
public User user(){
User user = new User();
user.setId(1L);
user.setName("宵宫");
return user;
}
}
什么是 BeanDefinition?
BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口, 包含:
BeanDefinition 构建
具体的代码如下:
package org.learn.spring.bean.definition;
import org.learn.spring.ioc.overview.domain.User;
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;
// BeanDefinition构建的实例
public class BeanDefinitionCreationDemo {
public static void main(String[] args) {
// 1.通过 BeanDefinitionBuilder 进行构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 通过属性设置
beanDefinitionBuilder.addPropertyValue("id", 1);
beanDefinitionBuilder.addPropertyValue("name", "神里绫华");
// 获取BeanDefinition实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// BeanDefinition并非Bean的终态 可以自定义修改
// 2.通过AbstractBeanDefinition 以及派生类
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
// 设置Bean的类型
genericBeanDefinition.setBeanClass(User.class);
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
// 通过 MutablePropertyValues 批量操作添加
// mutablePropertyValues.addPropertyValue("id",1);
// mutablePropertyValues.addPropertyValue("name","神里绫人");
// 链式的调用
mutablePropertyValues.add("id", 2).add("name", "神里绫人");
genericBeanDefinition.setPropertyValues(mutablePropertyValues);
}
}
Bean 的名称
Bean 名称生成器( BeanNameGenerator)
具体的代码:
public static String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
throws BeanDefinitionStoreException {
String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
else if (definition.getFactoryBeanName() != null) {
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
}
String id = generatedBeanName;
if (isInnerBean) {
// Inner bean: generate identity hashcode suffix.
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
}
else {
// Top-level bean: use plain class name with unique suffix if necessary.
return uniqueBeanName(generatedBeanName, registry);
}
return id;
}
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
Bean 别名( Alias) 的价值
复用现有的 BeanDefinition
更具有场景化的命名方法, 比如:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
具体的代码如下:
package org.learn.spring.bean.definition;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// bean别名示例
public class BeanAliasDemo {
public static void main(String[] args) {
// 配置XML 配置文件
// 启动spring的应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/bean-definitions-context.xml");
// 通过别名 hutao-user 获取曾用名 user 的 bean
User user = beanFactory.getBean("user", User.class);
User hutaoUser = beanFactory.getBean("hutao-user", User.class);
// true
System.out.println("user 和 hutaoUser 是否相等:"+(user == hutaoUser));
}
}
BeanDefinition 注册
具体的代码如下:
package org.learn.spring.bean.definition;
import org.learn.spring.ioc.overview.domain.User;
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 java.util.Map;
// 注解的BeanDefinition 示例
@Import(AnnotationBeanDefinitionDemo.Config.class)// 3.通过@Import的方式来导入
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
// 创建BeanFactory的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册Configuration Class 配置类
applicationContext.register(AnnotationBeanDefinitionDemo.class);
// 1.通过@Bean的方式定义
// 2.通过@Component的方式定义
// 3.通过@Import的方式来导入
// 通过 BeanDefinition API来实现
// 1.通过命名 Bean 方式来注册
registerUserBeanDefinition(applicationContext, "ganyu-user");
// 2.通过非命名 Bean 方式来注册
registerUserBeanDefinition(applicationContext);
// 启动应用上下文
applicationContext.refresh();
// 按照类型依赖查找
Map<String, Config> configBeans = applicationContext.getBeansOfType(Config.class);
Map<String, User> userBeans = applicationContext.getBeansOfType(User.class);
System.out.println("Config 类型的所有beans:" + configBeans);
System.out.println("User 类型的所有beans:" + userBeans);
// 显示的关闭spring应用上下文
applicationContext.close();
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
beanDefinitionBuilder.addPropertyValue("id", 1).addPropertyValue("name", "甘雨");
// 判断如果 beanName 参数存在时
if (StringUtils.hasText(beanName)) {
// 注册BeanDefinition
// 命名 Bean 的注册方式
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
} else {
// 非命名 Bean 的注册方式
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
}
}
public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
registerUserBeanDefinition(registry, null);
}
@Component // 定义当前类作为Spring Bean(组件)2.通过@Component的方式定义
public static class Config {
// 1.通过@Bean的方式定义
@Bean(name = {"user", "naxida-user"})
public User user() {
User user = new User();
user.setId(1L);
user.setName("纳西妲");
return user;
}
}
}
Bean 实例化( Instantiation)
具体的代码如下:
<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 id="user-by-static-method" class="org.learn.spring.ioc.overview.domain.User" factory-method="createUser"/>
<bean id="userFactory" class="org.learn.spring.bean.factory.DefaultUserFactory"/>
<bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
<bean id="user-by-factory-bean" class="org.learn.spring.bean.factory.UserFactoryBean"/>
beans>
package org.learn.spring.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;
}
public static User createUser(){
User user = new User();
user.setId(1L);
user.setName("温蒂");
return user;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
package org.learn.spring.bean.factory;
import org.learn.spring.ioc.overview.domain.User;
// User工厂类
public interface UserFactory {
default User createUser(){
return User.createUser();
}
}
package org.learn.spring.bean.factory;
// 默认的UserFactory的实现
public class DefaultUserFactory implements UserFactory{
}
package org.learn.spring.bean.factory;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.FactoryBean;
// User Bean 的 FactoryBean的实现
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return User.createUser();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
package org.learn.spring.bean.definition;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//Bean 实例化 示例
public class BeanInstantiationDemo {
public static void main(String[] args) {
// 配置XML 配置文件
// 启动spring的应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/bean-instantiation-context.xml");
User userByStaticMethod = 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(userByStaticMethod);
System.out.println(userByInstanceMethod);
System.out.println(userByInstanceMethod == userByStaticMethod);
System.out.println(userByFactoryBean);
}
}
下面可以通过我们的ServiceLoader的方式来实例化,先在resource
文件下创建一个文件夹META-INF/services
,然后在这个文件夹下创建一个文件,文件名为org.learn.spring.bean.factory.UserFactory
该文件名是全类名,然后内容是org.learn.spring.bean.factory.DefaultUserFactory
就是对应的实现。
<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 id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
<property name="serviceType" value="org.learn.spring.bean.factory.UserFactory"/>
bean>
beans>
package org.learn.spring.bean.definition;
import org.learn.spring.bean.factory.DefaultUserFactory;
import org.learn.spring.bean.factory.UserFactory;
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 java.util.Iterator;
import java.util.ServiceLoader;
//特殊的Bean 实例化 示例
public class SpecialBeanInstantiationDemo {
public static void main(String[] args) {
// 配置XML 配置文件
// 启动spring的应用上下文
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:META-INF/special-bean-instantiation-context.xml");
// 通过ApplicationContext 获取 AutowireCapableBeanFactory
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
ServiceLoader<UserFactory> serviceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);
displayServiceLoader(serviceLoader);
// 创建DefaultUserFactory对象 通过AutowireCapableBeanFactory
UserFactory userFactory = beanFactory.createBean(DefaultUserFactory.class);
System.out.println(userFactory.createUser());
}
public static void demoServiceLoader() {
ServiceLoader<UserFactory> serviceLoader = 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());
}
}
}
Bean 初始化( Initialization)
具体的代码如下:
package org.learn.spring.bean.factory;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
// 默认的UserFactory的实现
public class DefaultUserFactory implements UserFactory, InitializingBean {
// 1. 通过 @PostConstruct 实现
@PostConstruct
public void init(){
System.out.println("@PostConstruct: UserFactory 初始化中....");
}
public void initUserFactory(){
System.out.println("自定义初始化方法initUserFactory(): UserFactory 初始化中....");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean#afterPropertiesSet(): UserFactory 初始化中....");
}
}
package org.learn.spring.bean.definition;
import org.learn.spring.bean.factory.DefaultUserFactory;
import org.learn.spring.bean.factory.UserFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// Bean 初始化Demo
@Configuration //Configuration class
public class BeanInitializationDemo {
public static void main(String[] args) {
// 创建BeanFactory的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册Configuration Class 配置类
applicationContext.register(BeanInitializationDemo.class);
// 启动spring的应用上下文
applicationContext.refresh();
// 依赖查找 userFactory
UserFactory userFactory = applicationContext.getBean(UserFactory.class);
// 关闭spring的应用上下文
applicationContext.close();
}
@Bean(initMethod = "initUserFactory")
public UserFactory userFactory(){
return new DefaultUserFactory();
}
}
思考: 假设以上三种方式均在同一 Bean 中定义, 那么这些方法的执行顺序是怎样?运行的结果如下:
可以看出先是@PostConstruct
,再是InitializingBean
的实现的方法,最后才是我们的自定义的方法。
Bean 延迟初始化( Lazy Initialization)
思考: 当某个 Bean 定义为延迟初始化, 那么, Spring 容器返回的对象与非延迟的对象存在怎样的差异?
package org.learn.spring.bean.definition;
import org.learn.spring.bean.factory.DefaultUserFactory;
import org.learn.spring.bean.factory.UserFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
// Bean 初始化Demo
@Configuration //Configuration class
public class BeanInitializationDemo {
public static void main(String[] args) {
// 创建BeanFactory的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册Configuration Class 配置类
applicationContext.register(BeanInitializationDemo.class);
// 启动spring的应用上下文
applicationContext.refresh();
// 非延迟初始化在spring应用上下文启动完成后,被初始化
System.out.println("spring应用上下文已启动....");
// 依赖查找 userFactory
UserFactory userFactory = applicationContext.getBean(UserFactory.class);
System.out.println(userFactory);
// 关闭spring的应用上下文
applicationContext.close();
}
@Bean(initMethod = "initUserFactory")
@Lazy
public UserFactory userFactory(){
return new DefaultUserFactory();
}
}
运行的结果如下:
可以看出非延迟化的Bean,是在spring应用上下文启动后,需要使用的时候才会创建。
我们来修改一下代码,将UserFactory改成非lazy的。
package org.learn.spring.bean.definition;
import org.learn.spring.bean.factory.DefaultUserFactory;
import org.learn.spring.bean.factory.UserFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
// Bean 初始化Demo
@Configuration //Configuration class
public class BeanInitializationDemo {
public static void main(String[] args) {
// 创建BeanFactory的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册Configuration Class 配置类
applicationContext.register(BeanInitializationDemo.class);
// 启动spring的应用上下文
applicationContext.refresh();
// 非延迟初始化在spring应用上下文启动完成后,被初始化
System.out.println("spring应用上下文已启动....");
// 依赖查找 userFactory
UserFactory userFactory = applicationContext.getBean(UserFactory.class);
System.out.println(userFactory);
// 关闭spring的应用上下文
applicationContext.close();
}
@Bean(initMethod = "initUserFactory")
//@Lazy
public UserFactory userFactory(){
return new DefaultUserFactory();
}
}
运行结果如下:
可以看到非lazy的Bean在spring应用上下文启动完成前,这个Bean已经实例化完成了。
Bean 销毁( Destroy)
现在看如下的代码:
package org.learn.spring.bean.factory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
// 默认的UserFactory的实现
public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {
// 1. 通过 @PostConstruct 实现
@PostConstruct
public void init(){
System.out.println("@PostConstruct: UserFactory 初始化中....");
}
public void initUserFactory(){
System.out.println("自定义初始化方法initUserFactory(): UserFactory 初始化中....");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean#afterPropertiesSet(): UserFactory 初始化中....");
}
@PreDestroy
public void preDestroy(){
System.out.println("@PreDestroy: UserFactory 销毁中....");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean#destroy(): UserFactory 销毁中....");
}
public void doDestroy() throws Exception {
System.out.println("自定义销毁方法doDestroy(): UserFactory 销毁中....");
}
}
package org.learn.spring.bean.definition;
import org.learn.spring.bean.factory.DefaultUserFactory;
import org.learn.spring.bean.factory.UserFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
// Bean 初始化Demo
@Configuration //Configuration class
public class BeanInitializationDemo {
public static void main(String[] args) {
// 创建BeanFactory的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册Configuration Class 配置类
applicationContext.register(BeanInitializationDemo.class);
// 启动spring的应用上下文
applicationContext.refresh();
// 非延迟初始化在spring应用上下文启动完成后,被初始化
System.out.println("spring应用上下文已启动....");
// 依赖查找 userFactory
UserFactory userFactory = applicationContext.getBean(UserFactory.class);
System.out.println(userFactory);
System.out.println("spring应用上下文准备关闭....");
// 关闭spring的应用上下文
applicationContext.close();
System.out.println("spring应用上下文已关闭....");
}
@Bean(initMethod = "initUserFactory",destroyMethod = "doDestroy")
//@Lazy
public UserFactory userFactory(){
return new DefaultUserFactory();
}
}
思考: 假设以上三种方式均在同一 Bean 中定义, 那么这些方法的执行顺序是怎样?运行的结果如下:
可以看出先是@PreDestroy
,再是DisposableBean
的实现的方法,最后才是我们的自定义的方法。从上面的运行的结果我们可以发现是close()
触发了这些方法。
Bean 垃圾回收( GC)
具体的代码如下:
package org.learn.spring.bean.factory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
// 默认的UserFactory的实现
public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {
// 1. 通过 @PostConstruct 实现
@PostConstruct
public void init(){
System.out.println("@PostConstruct: UserFactory 初始化中....");
}
public void initUserFactory(){
System.out.println("自定义初始化方法initUserFactory(): UserFactory 初始化中....");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean#afterPropertiesSet(): UserFactory 初始化中....");
}
@PreDestroy
public void preDestroy(){
System.out.println("@PreDestroy: UserFactory 销毁中....");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean#destroy(): UserFactory 销毁中....");
}
public void doDestroy() throws Exception {
System.out.println("自定义销毁方法doDestroy(): UserFactory 销毁中....");
}
@Override
protected void finalize() throws Throwable {
System.out.println("当前 DefaultFactory 对象正在被垃圾回收...");
}
}
package org.learn.spring.bean.definition;
import org.learn.spring.bean.factory.UserFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class BeanGarbageCollectionDemo {
public static void main(String[] args) {
// 创建BeanFactory的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册Configuration Class 配置类
applicationContext.register(BeanInitializationDemo.class);
// 启动spring的应用上下文
applicationContext.refresh();
// 关闭spring的应用上下文
applicationContext.close();
// 强制触发 GC
System.gc();
}
}
运行的结果如下:
这儿需要注意的是,虽然我们调用了 System.gc();
方法,但是也不一定会强制触发GC的,我这儿多调用了几次,才触发了GC。
Spring makes it easy to create Java enterprise applications. It provides everything you need to embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as alternative languages on the JVM, and with the flexibility to create many kinds of architectures depending on an application’ s needs.
Spring 使创建 Java 企业应用程序变得容易。 它提供了在企业环境中使用 Java 语言所需的一切,支持 Groovy 和 Kotlin 作为 JVM 上的替代语言,并且可以根据应用程序的需要灵活地创建多种架构。
简单地说, IoC 是反转控制, 类似于好莱坞原则, 主要有依赖查找和依赖注入实现
依赖查找是主动或手动的依赖查找方式, 通常需要依赖容器或标准 API实现。 而依赖注入则是手动或自动依赖绑定的方式, 无需依赖特定的容器和API
Spring Framework implementation of the Inversion of Control (IoC) principle. IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when itcreates the bean.
Spring Framework 实现了控制反转(IoC)的原理。 IoC 也称为依赖注入 (DI)。 在这个过程中,对象仅通过构造函数参数、工厂方法的参数或在对象实例被构造或从工厂方法返回后设置的属性来定义它们的依赖关系(即它们使用的其他对象) . 然后容器在创建 bean 时注入这些依赖项。
IoC 配置元信息读取和解析、 IoC 容器生命周期、 Spring 事件发布、国际化等。后续的章节会详细的讨论。
通过 BeanDefinition 和外部单体对象来注册
定义 Spring Bean 和 BeanDefinition 元信息
IoC 配置元信息读取和解析、 依赖查找和注入以及 Bean 生命周期等。后面的章节会继续讨论。