Spring Bean 作用域
单例模式
singleton Bean 作用域:在BeanFactory中唯一。
原型模式
prototype Bean 作用域:

servlet 引擎:
request Bean 作用域: 将Spring Bean 存储在Servlet Request上下文中
session Bean 作用域:将SpringBean存储在HttpSession中
application bean 作用域:将SpringBean存储在ServletContext中。
自定义Bean 作用域

Spring BeanFactory 类图

BeanFactory是访问Spring bean容器的根接口。提供了一些获取Bean的基础方法定义。

BeanFactory

ListableBeanFactory 和 ConfigurableBeanFactory 提供了一些更具体的特殊目标。

ListableBeanFactory继承了BeanFactory, 容器可以以列表的形式获取bean的相关信息,提供了获取多个beanName的基础方法。
ListableBeanFactory

ConfigurableBeanFactory 继承了 hierarchicalBeanFactory, 提供了IOC容器的可配置能力,几乎所有的BeanFactory都会实现这个接口。
ConfigurableBeanFactory

AutowireCapableBeanFactory 提供了自动装配Bean的能力。

AutowireCapableBeanFactory

依赖注入的模式和类型

  • 手动
    • Xml资源配置元信息
    • Java注解配置元信息
      • @Bean
      • @Autowired
    • API配置元信息
  • 自动
    • Autowiring
    • 类型
      • No : 默认值,未激活自动绑定,需要手动指定依赖注入
      • byName: 根据被注入属性的名称做为Bean名称进行依赖查找,并将对象设置到该属性
      • byType: 根据被注入属性的类型做为依赖类型进行查找,并将对象设置到该属性
      • constructor: 特殊的byType,用于构造器参数

xml 资源配置元信息

1
2
3
<bean id="" name="" class="">
<property name="name" ref="nameObj"/>
</bean>
依赖注入类型 示例
set <property name=”user” ref=”userBean”/>
构造器 <constructor-arg name=”user” ref=”userBean”/>
字段注入 @Autowired User user;
方法注入 @Autowired public void user(User user){}
回调注入 class MyBean implements BeanFactoryAware{}

依赖注入选择

基础类型注入
集合类型注入
限定注入
延迟依赖注入
依赖处理过程
@Autowired 注入原理
JSR-330@inject注入原理
Java通用注解注入原理
自定义依赖注解

自动绑定
模式
限制和不足

题目精选

依赖查找

历史

单一类型依赖查找

JNDI - javax.naming.Context#lookup*(javax.naming.Name);
JavaBeans - java.beans.beancontext.BeanContext

  • BeanFactory:
    • 根据bean名称查找
      • getBean(String);
      • getBean(String,Object…) //覆盖默认参数
    • 根据Bean类型查找
      • bean实时查找
        • getBean(Class)
        • getBean(Class,Object…)//覆盖默认参数
      • bean延时查找
        • getBeanProvider(Class);
        • getBeanProvider(String,Class);
    • 根据Bean名称和类型查找
      • getBean(String,Class);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 通过 {@link org.springframework.beans.factory.ObjectProvider} 进行依赖查找
*/
public class ObjectProviderDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ObjectProviderDemo.class);
applicationContext.refresh();
lookupByObjectProvider(applicationContext);
applicationContext.close();
}

@Bean
public String helloWorld() {
return "Hello World";
}
private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
System.out.println(objectProvider.getObject());
}
}

集合类型依赖查找

java.beans.beancontext.BeanContext

ListableBeanFactory

是针对某个类型去查找一个集合列表。
一种是查询bean的名称, 一种是查询bean的实例。
一般情况下应该使用bean的名称来判断当前bean是否存在,或者进一步判断BeanDefinition是否存在。
而查询bean实例会提早初始化bean实例,造成初始化不完整。

  • 根据Bean类型查找
    • 获取同类型Bean名称列表
      • getBeanNamesForType(Class)
      • getBeanNamesForType(ResolvableType)
    • 获取痛类型Bean实例列表
      • getBeansOfType(Class)以及重载方法
  • 根据注解类型查找
    • 获取标注类型Bean 名称列表
      • getBeanNamesForAnnotation(Class<? extends Annotation>);
    • 获取标注类型Bean实例列表
      • getBeansWithAnnotation(Class<? extends Annotation>);
    • 获取指定名称+标注类型实例
      • findAnnotationOnBean(String,Class<? extends Annotation>);

层次性依赖查找

java.beans.beancontext.BeanContext

HierachicalBeanFactory

  • 双亲 BeanFactory: getParentBeanFactory();
    • 层次查找
    • 根据Bean名称查找
      • 基于containsLocalBean方法实现
    • 根据Bean类型查找实例列表
      • 单一类型:BeanFactoryUtils#beanOfType
      • 集合类型:BeanFactoryUtils#beansOfTypeIncludingAncestors
    • 根据Java注解查找名称列表
      • BeanFactoryUtils#beanNamesForTypeIncludingAncestors
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
public class HierarchicalDependencyLookupDemo {


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

ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();

HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();

beanFactory.setParentBeanFactory(parentBeanFactory);

displayContainsLocalBean(beanFactory, "user"); //false
displayContainsLocalBean(parentBeanFactory, "user"); //true

displayContainsBean(beanFactory, "user"); //true
displayContainsBean(parentBeanFactory,"user");//true

applicationContext.refresh();
applicationContext.close();
}


private static void displayContainsBean(HierarchicalBeanFactory beanFactory, String beanName) {
System.out.printf("当前 BeanFactory [%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 parentBeanFactory, String user) {
System.out.printf("当前 BeanFactory [%s] 是否包含 Local bean[name:%s] %s\n", parentBeanFactory, user, parentBeanFactory.containsLocalBean(user));
}

private static HierarchicalBeanFactory createParentBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String location = "classpath:applicationContext-lookup.xml";
reader.loadBeanDefinitions(location);
return beanFactory;
}
}

延迟依赖查找

  • Bean延迟依赖查找接口
    • org.springframework.beans.factory.ObjectFactory#getObject();
    • org.springframework.beans.factory.ObjectProvider
      • Spring5对于Java8的特性扩展
      • 函数式接口
        • getIfAvailable(Supplier)
        • ifAvailable(Consumer)
      • Stream扩展 - stream()
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
/**
* 通过 {@link org.springframework.beans.factory.ObjectProvider} 进行依赖查找
*/
public class ObjectProviderDemo {


public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ObjectProviderDemo.class);
applicationContext.refresh();

lookupByObjectProvider(applicationContext);
lookupIfAvailable(applicationContext);
lookupByStream(applicationContext);
applicationContext.close();
}

private static void lookupByStream(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
// Iterator<String> iterator = objectProvider.iterator();
// while(iterator.hasNext()){
// System.out.println(iterator.next());
// }
objectProvider.stream().forEach(System.out::println);
}

private static void lookupIfAvailable(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
User user = userObjectProvider.getIfAvailable(User::new);
System.out.println(user);

}

@Bean
@Primary
public String helloWorld() {
return "Hello World";
}

@Bean
public String message(){
return "message";
}

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

安全依赖查找

依赖查找安全性对比

依赖查找类型 代表实现 是否安全
单一类型查找 BeanFactory#getBean
ObjectFactory#getObject
ObjectProvider#getIfAvailable
集合类型查找 ListableBeanFactory#getBeansOfType
ObjectProvider.stream
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
import com.github.springframework.models.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TypeSafetyDependencyLookupDemo {

public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(TypeSafetyDependencyLookupDemo.class);
applicationContext.refresh();

displayBeanFactoryGetBean(applicationContext);
displayObjectFactoryGetObject(applicationContext);
displayObjectProviderIfAvailable(applicationContext);

displayListableBeanFactoryGetBeansOfType(applicationContext);

displayObjectProviderStreamOps(applicationContext);
applicationContext.close();
}

public static void displayObjectProviderStreamOps(AnnotationConfigApplicationContext beanFactory){
ObjectProvider<User> userObjectFactory = beanFactory.getBeanProvider(User.class);
printException("displayObjectProviderStreamOps", ()->userObjectFactory.forEach(System.out::println));
}

public static void displayListableBeanFactoryGetBeansOfType(ListableBeanFactory beanFactory){
printException("displayListableBeanFactoryGetBeansOfType", ()->beanFactory.getBeansOfType(User.class));
}

public static void displayObjectProviderIfAvailable(BeanFactory beanFactory){
ObjectProvider<User> userObjectFactory = beanFactory.getBeanProvider(User.class);
printException("displayObjectProviderIfAvailable", ()->userObjectFactory.getIfAvailable());
}

public static void displayObjectFactoryGetObject(BeanFactory beanFactory){
ObjectProvider<User> userObjectFactory = beanFactory.getBeanProvider(User.class);
printException("displayObjectFactoryGetObject", ()->userObjectFactory.getObject());
}

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

public static void printException(String source, Runnable run){
System.out.println("Source From : " + source);
System.out.println("======================================");
try{
run.run();
}catch (BeansException e){
e.printStackTrace();
}
}
}

内建可查找的依赖

  • AbstractApplicationContext 内建可查找依赖
Bean名称 Bean实例 使用场景
environment Environment对象 外部化配置以及Profiles
systemProperties java.util.Proerties对象 Java系统属性
systemEnvironment java.util.Map对象 操作系统环境变量
messageSource MessageSource对象 国际化文案
lifecycleProcessor LifecycleProcessor对象 LifecycleBean处理器
applicationEventMulticaster ApplicationEventMulticaster对象 Spring事件广播器
  • 注解驱动Spring上下文内建可查找的依赖

AnnotationConfigUtils.

Bean名称 Bean实例 使用场景
org.springframework.context.annotation.internalConfigurationAnnotationProcessor ConfigurationClassPostProcessor对象 处理Spring配置类
org.springframework.context.annotation.internalAutowiredAnnotationProcessor AutowireAnnotationBeanPostProcessor对象 处理@Autowired以及@Value注解
org.springframework.context.annotation.internalCommonAnnotatinProcessor CommonAnnotationBeanPostProcessor对象 条件激活处理JSR-250注解,如@PostConstruct
org.springframework.context.event.internalEventListenerProcessor EventListenerMethodProcessor对象 处理@EventListener的Spring事件监听方法

依赖查找中的异常

  • NoSuchBeanDefinitionException
  • NoUniqueBeanDefinitionException
  • BeanInstantiationException
  • BeanCreationException
  • BeanDefinitionStoreException

常见题目

  • ObjectFactory 和 BeanFactory 的区别
  • BeanFactory.getBean 的线程安全性

BeanDefinition

A BeanDefinition describes a bean instance, which has property values,
Constructor arguments values, and further information supplied by concrete implementations.
This is just a minimal interface: The main intention is to allow a BeanFactoryPostProcessor to introspect and modify property values and other bean metadata.

BeanDefinition 类图

BeanDefinition: 顶级父接口,继承了BeanMetadataElement和AttributeAccessor.

AbstractBeanDefinition:是GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition 的通用属性的完整实现。
GenericBeanDefinition: 标准的bean定义目的的一站式服务类.
RootBeanDefinition: 根Bean定义,代表合并的BeanDefinition。
ChildBeanDefinition: 有parent的BeanDefinition

BeanDefinition是SpringFramework中定义的配置元信息接口,包含了:

  • Bean 的类名
  • Bean 的行为配置元素,如作用域、自动绑定模式、生命周期回调等
  • 其他Bean引用,(Collaborators、Dependends)
  • 配置设置(Bean的Properties)

BeanDefinition 元信息

属性 说明
Class Bean的全限类名,必须是具体类
Name Bean的名称或者🆔
Scope Bean的作用域,singleton、prototype
Constructor arguments Bean的构造器参数 for DI
Properties Bean的属性设置 for DI
Autowiring Mode Bean的自动绑定模式:ByName 、 byType
Lazy Initialization Mode Bean 延迟初始化模式
initialzation method Bean初始化回调方法名称
destruction method Bean 销毁回调方法名称

BeanDefinition 构建

  • 通过BeanDefinitionBuilder构建Beandefinition
1
2
3
4
5
6
7
        //bean definition builder.
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);

beanDefinitionBuilder.addPropertyValue("id",1L);
beanDefinitionBuilder.addPropertyValue("name","lisi");

BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
  • 通过GenericBeanDefinition 构建
1
2
3
4
5
6
7
8
9
10
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(User.class);

MutablePropertyValues propertyValues = new MutablePropertyValues();
// propertyValues.addPropertyValue("id",2L);
// propertyValues.addPropertyValue("name","zhaowu");

propertyValues.add("id",2L)
.add("name","zhaowu");
genericBeanDefinition.setPropertyValues(propertyValues);

SpringBean 命名

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

在基于XML的配置元信息中,可以使用id或者name属性来规定Bean的标识符。通常Bean的标识符由字母组成,允许出现特殊字符。可以在Bean的name属性使用逗号“,”或者“;”或者空格来间隔名称做为别名。

Bean的id或者name属性如果为空,容器会为Bean自动生成一个唯一的名称。

BeanNameGenerator

BeanNameGenerator 类图

DefaultBeanNameGenerator

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
/**
* Generate a bean name for the given bean definition, unique within the
* given bean factory.
* @param definition the bean definition to generate a bean name for
* @param registry the bean factory that the definition is going to be
* registered with (to check for existing bean names)
* @param isInnerBean whether the given bean definition will be registered
* as inner bean or as top-level bean (allowing for special name generation
* for inner beans versus top-level beans)
* @return the generated bean name
* @throws BeanDefinitionStoreException if no unique name can be generated
* for the given bean definition
*/
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;
}

由代码可以看出, 首先获取BeanClassName, BeanClassName 为空时,获取ParentName,ParentName为空时获取FactoryBeanName, 当三者都为空的时候名称是无法创建的。 三者不为空时生成的名称前缀为:
BeanClassName
ParentName$child
FactoryBeanName$created

在生成名字时,如果是内部类, 则生成名字为前缀+#+当前beanDefinition的hashCode, 如下:
BeanClassName#hashCode
ParentName$child#hashCode
FactoryBeanName$created#hashCode

如果不是内部类, 则调用uniqueBeanName生成唯一的BeanName,格式为 + “#” + 序号。

BeanClassName#1
ParentName$child#1
FactoryBeanName$created#1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Turn the given bean name into a unique bean name for the given bean factory,
* appending a unique counter as suffix if necessary.
* @param beanName the original bean name
* @param registry the bean factory that the definition is going to be
* registered with (to check for existing bean names)
* @return the unique bean name to use
* @since 5.1
*/
public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
String id = beanName;
int counter = -1;

// Increase counter until the id is unique.
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = beanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
return id;
}

AnnotationBeanNameGeneritor

先判断是否为AnnotatedBeanDefinition, 优先按照AnnotationBeanDefinition配置的Value获取,如果没有配置,则按照缺省的方式来生成beanName(如果是mypackage.MyJdbcDao 则生成 myJdbcDao)。

1
2
3
4
5
6
7
8
9
10
11
12
@Override
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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Derive a default bean name from the given bean definition.
* <p>The default implementation simply builds a decapitalized version
* of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
* <p>Note that inner classes will thus have names of the form
* "outerClassName.InnerClassName", which because of the period in the
* name may be an issue if you are autowiring by name.
* @param definition the bean definition to build a bean name for
* @return the default bean name (never {@code null})
*/
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}

BeanDefinition 配置

Xml

1
2
3
4
5
6
7
8
9
10
11
12
<bean id="user" class="com.github.springframework.models.User" primary="true">
<property name="id" value="1"/>
<property name="name" value="zhangsan"/>
</bean>

<bean id="superUser" class="com.github.springframework.models.SuperUser" parent="user" >
<property name="addr" value="上海"/>
</bean>

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

Java注解 @Bean

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
public class AnnotationBeanDefinitionDemo {


public static void main(String[] args) {

//create factory bean
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

//register config class.
applicationContext.register(Config.class);

//refresh
applicationContext.refresh();

//getUser
System.out.println(applicationContext.getBean(User.class));
}



static class Config{
@Bean
public User user(){
User user = new User();
user.setId(1L);
user.setName("Ann: zhangsan");
return user;
}
}
}

Java注解 @Component

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
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
//create factory bean
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

//register config class.
applicationContext.register(Config.class);

//refresh
applicationContext.refresh();

//
System.out.println(applicationContext.getBean(Config.class));
}
@Component
static class Config{
@Bean
public User user(){
User user = new User();
user.setId(1L);
user.setName("Ann: zhangsan");
return user;
}
}
}

BeanDefinition注册到容器

BeanDefinitionRegistry 提供了 BeanDefinition 的注册、删除,获取,判断是否存在等功能。

BeanDefinitionRegistry 类图1

BeanDefinitionRegistry 类图2

1
2
3
4
5
6
7
8
9
10
static void beanDefinitionRegistry(BeanDefinitionRegistry registry, String name) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
beanDefinitionBuilder.addPropertyValue("id", 1L)
.addPropertyValue("name", "Reg: zhangsan");
if (StringUtils.hasText(name)) {
registry.registerBeanDefinition(name, beanDefinitionBuilder.getBeanDefinition());
} else {
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(),registry);
}
}

由于AnnotatinoConfigApplicationContext 是 BeanDefinitionRegistry的间接子类。

1
2
3
4
5
6
7
8
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Config.class);
beanDefinitionRegistry(applicationContext,"REG:ZhangSan:Name");
beanDefinitionRegistry(applicationContext,null);
applicationContext.refresh();
System.out.println(applicationContext.getBeansOfType(Config.class));
System.out.println(applicationContext.getBeansOfType(User.class));
System.out.println(applicationContext.getBeansOfType(AnnotationApplicationContextDemo.class));

Bean 实例化

常规:

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

  • 静态工厂方法(配置元信息:XML、JavaAPI)

1
2
3
4
5
6
7
8
9
10
public class User2 {

private Long id;

private String name;

public static User2 getInstance(){
return new User2();
}
}
1
<bean id="user-by-static-method" class="com.github.spring.beans.User2"  factory-method="getInstance"></bean>
1
2
3
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-creation-context.xml");

User2 user = applicationContext.getBean("user-by-static-method", User2.class);
  • Bean工厂方法(配置元信息:XML、JavaAPI)
1
2
3
4
5
6
7
8
public interface UserFactory {
default User2 createuser() {
return new User2();
}
}

public class DefaultUserFactory implements UserFactory {
}
1
2
<bean id="userFactory" class="com.github.spring.factory.DefaultUserFactory"/>
<bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createuser"/>
1
2
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-creation-context.xml");
User2 user3 = applicationContext.getBean("user-by-instance-method", User2.class);
  • FactoryBean(XML、Java注解、JavaAPI)
1
2
3
4
5
6
7
8
9
10
11
12
public class UserFactoryBean implements FactoryBean<User2> {

@Override
public User2 getObject() throws Exception {
return User2.getInstance();
}

@Override
public Class<?> getObjectType() {
return User2.class;
}
}
1
<bean id="user-by-factory-bean" class="com.github.spring.factory.UserFactoryBean"/>
1
2
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-creation-context.xml");
User2 user2 = applicationContext.getBean("user-by-factory-method", User2.class);

特殊方式:

  • ServiceLoaderFactoryBean

Java ServiceLoader: 会在classpath:/META-INF/services下加载接口配置文件:

文件名名称为全限定接口名称,内容为全限定实现类

services 配置文件

1
com.github.spring.factory.DefaultUserFactory
1
2
3
4
5
6
7
8
9
10
11
12
public static void demoServiceLoader() {
ServiceLoader<UserFactory> serviceLoader = ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader());
displayServiceLoad(serviceLoader);
}

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

ServiceLoaderFactoryBean的实现

1
2
3
<bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
<property name="serviceType" value="com.github.spring.factory.UserFactory"/>
</bean>
1
2
3
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/sp-bean-creation-context.xml");
ServiceLoader<UserFactory> serviceLoader = applicationContext.getBean("userFactoryServiceLoader", ServiceLoader.class);
displayServiceLoad(serviceLoader);
  • AutowireCapableBeanFactory#createBean(java.lang.Class,int, boolean);
1
2
3
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
UserFactory userFactory = beanFactory.createBean(DefaultUserFactory.class);
System.out.println(userFactory.createuser());
  • BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition);

Bean的初始化

  • @PostConstructor

  • InitializingBean 的 afterPropertiesSet

  • Bean的initMethod
    @Bean(initMethod=””)

    AbstractBeanDefinition.setInitMethodName("");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class DefaultUserFactory implements UserFactory, InitializingBean {

public DefaultUserFactory() {
System.out.println("DefaultUserFactory Constructor Called.");
}

@PostConstruct
public void init(){
System.out.println("DefaultUserFactory PostConstructor Called.");
}

public void initUserFactory(){
System.out.println("DefaultUserFactory initUserFactory Called.");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("DefaultUserFactory afterPropertiesSet called.");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
public class BeanInitializationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(BeanInitializationDemo.class);
applicationContext.refresh();
UserFactory userFactory = applicationContext.getBean(UserFactory.class)
System.out.println(userFactory.createuser());
applicationContext.close();
}

@Bean(initMethod = "initUserFactory")
public DefaultUserFactory userFactory(){
return new DefaultUserFactory();
}
}

延迟初始化

  • xml:
  • annotation: @Lazy

对于延迟初始化,是在applicationContext初始化之后进行初始化。
非延迟初始化,是在applicationContext初始化之前进行初始化。

Bean 的销毁

  • @PreDestroy
  • 实现DisposableBean接口的destoy()方法
  • Bean的 destroy方法 @Bean(destroy="") AbstractBeanDefinition.setDestroyMethodName("");

  • 如何注册一个Spring Bean

可以通过BeanDefinition和外部单体对象来注册。

1
2
3
4
5
UserFactory userFactory = new DefaultUserFactory();
ConfiguableListableBeanFactory factory = applicationContext.getBeanFactory();
factory.registerSingleton("userFactory", userFactory);

UserFactory userFactory = applicationContext.getBean("UserFactory",UserFactory.class);
  • Spring BeanDefinition 是什么?

  • Spring 容器是如何注册Bean的?

IOC 简史

  • 1983年,Richard E.Sweet 在<>提出好莱坞原则(“不要打电话给我,我会打电话给你”)。
  • 1988年,Rolph E.Johnson 和Brian Foote在《Designing Reusable Classes》中提出控制反转。
  • 1996年,Michael Mattson在《Object-Oriented Frameworks, A survey of methodological issues》将控制反转命名为好莱坞原则。
  • 2004,Martin Fowler在《Inversion Of Control Containers and the Dependency Injection pattern》提出自己对和IOC和DI的理解
  • 2005年,Martin Folower在《Inversion Of Control》中对IOC进一步说明。
  • Martin 大爷关于IOC的说明

IOC 的实现策略

WIKI:

In object-oriented programming, there are several basic techniques to implement inversion of control. there are:

  • Using a service locator pattern
  • Using dependency injection
    • constructor injection
    • parameter injection
    • setter injection
    • interface injection
  • Using a contextualized lookup.
  • Using template method design pattern
  • Using Strategy design pattern.

EXPERT ONE-ON-ONE J2EE DEVELOPMENT without EJB提到的策略:

Spring相关内容来源于Spring官方网站与Spring源码。

Spring 5.2.7

Spring框架为企业级应用提供了一个完整的配置开发模型,可以在任何类型的发布平台。
Spring专注于企业应用的管道,保证开发团队专注于企业的业务逻辑,而不需要关注发布平台。

功能

核心技术

  • Dependency Injection依赖注入
  • events 事件
  • resources 资源管理
  • i18n 国际化
  • validation 校验
  • data binding 数据绑定
  • type conversion 类型转换
  • SpEL
  • AOP Aspect Oriented Programming 面向切面编程

测试

  • Mock Objects: 模拟对象
  • TestContext framework: 测试上下文框架
  • Spring MVC Test: MVC测试框架
  • WebTestClient: web测试客户端

DataAccess

  • transactions: 事务
  • DAO Support: DAO 支持
  • JDBC:
  • ORM:
  • Marshalling XML

Spring MVC

Spring WebFlux

Integration

  • remoting
  • JMS
  • JCA
  • JMX
  • email
  • tasks
  • scheduling
  • cache

Languages

  • Kotlin
  • Groovy
  • dynamic languages.

动静分离技术:CDN、
负载均衡:
实现手段:
1) lvs / lb / 四层数据包, 速度快,不解包。

2)   反向代理(nginx 、 Node.js 七层  URI/location 建立三次握手,请求传递、转发
      存储ip、请求uri、次数、时间等,
     )

     Load Balance 健康检查

算法:
随机
轮训
哈希
最少连接数

权重/动态权重

多级缓存
防穿透

限流
熔断
降级
灰度发布

服务无状态:分布式问题

update user set status = 2 where status = 1 and id = 1;

HotSpot 虚拟机常用配置

配置 说明
-Xms1g 最小堆内存
-Xmx4g 最大堆内存
-XX:+UseG1GC 使用G1垃圾回收器
-Xss256k 每个线程栈大小256k
-XX:MetaspaceSize=256m 元数据区大小256M
-XX:MaxMetaspaceSize=256m 元数据区最大256M
-XX:MaxGCPauseMillis=500 GC最大停顿毫秒数
-XX:+DisableExplicitGC 禁用代码中显式调用GC,System.gc()将会失效
-XX:+UnlockExperimentalVMOptions 解锁实验参数
-XX:+UseStringDeduplication GC的同时做重复字符串消除,只用于G1
-XX:InitiatingHeapOccupancyPercent=60 启动并发GC周期时的堆内存占用百分比. G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比. 值为 0 则表示”一直执行GC循环”. 默认值为 45.
-XX:ParallelGCThreads=8 设置垃圾收集器在并行阶段使用的线程数,默认值随JVM运行的平台不同而不同.
-XX:G1MixedGCCountTarget=4 设置在标记周期完成之后混合收集的数量,以维持old region(也就是老年代)中,最多有G1MixedGCLiveThresholdPercent的存活对象。默认值为8,混合收集的数量将维持在这个值之内。(JVM build > 23)
-XX:MaxTenuringThreshold=7 年老代的最大临界值(tenuring threshold). 默认值为 15.
-XX:+UseGCLogFileRotation 滚动记录GC日志文件
-XX:NumberOfGCLogFiles=5 GC日志文件数量为5个
-XX:GCLogFileSize=64M 单个GC日志文件大小64M
-Xloggc:/app/data/logs/gc-date +%Y%m%d-%H-%M.log GC日志文件存储目录和名称
-XX:+PrintGCDetails 打印GC详情
-XX:+PrintGCDateStamps 打印GC时时间戳
-XX:+PrintHeapAtGC GC时打印堆信息
-XX:+PrintAdaptiveSizePolicy 自适应大小策略,每次 GC 后会重新计算 Eden、From 和 To 区的大小,计算依据是 GC 过程中统计的 GC 时间、吞吐量、内存占用量。
-XX:+UseFastAccessorMethods
-XX:SoftRefLRUPolicyMSPerMB=0 softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap