Spring ioc容器

Spring Ioc依赖查找

pojo 定义

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 User {

private String id ;

private String name;

public String getId() {
return id;
}

public void setId(String 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 + '\'' +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@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();
}
}

实时查找

查找方式分根据bean id 查询、根据bean类型查找。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<bean id="user" class="com.thinking.in.spring.ioc.domian.User">
<property name="id" value="123"/>
<property name="name" value="liugd"/>
</bean>
</beans>
1
2
3
4
5
6
7
// 配置xml配置文件
// 启动Spring 加载上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext(" classpath:META-INFO/Dependency-lookup-context.xml");
// 根据bean id查询
User user = (User)beanFactory.getBean("user");
System.out.println("实时查找:"+user.toString());

延时查找

ObjectFactory方式查询bean,间接通过org.springframework.beans.factory.ObjectFactory获取bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<bean id="user" class="com.thinking.in.spring.ioc.domian.User">
<property name="id" value="123"/>
<property name="name" value="liugd"/>
</bean>

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

</beans>
1
2
3
4
5
6
7
8
    // 配置xml配置文件
// 启动Spring 加载上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext(" classpath:META-INF/Dependency-lookup-context.xml");
// 根据bean id "objectFactory" 获取ObjectFactory
ObjectFactory<User> objectFactory = (ObjectFactory<User>)beanFactory.getBean("objectFactory");
//
User user = objectFactory.getObject();
System.out.println("objectFactory延时查找:"+user.toString());

bean类型查找

通过ListableBeanFactory获取集合bean

1
2
3
4
5
6
7
8
// 配置xml配置文件
// 启动Spring 加载上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext(" classpath:META-INF/Dependency-lookup-context.xml");
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("查找到的所有的 User 集合对象:" + users);
}

java注解查询bean

根据super 注解去查询对应的bean对象。

1
2
3
4
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Super {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<bean id="user" class="com.thinking.in.spring.ioc.domian.User">
<property name="id" value="123"/>
<property name="name" value="liugd"/>
</bean>

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

<bean id="superUser" class="com.thinking.in.spring.ioc.domian.SuperUser" parent="user" primary="true">
<property name="address" value="北京"/>
</bean>

</beans>
1
2
3
4
5
6
7
8
// 配置xml配置文件
// 启动Spring 加载上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext(" classpath:META-INF/Dependency-lookup-context.xml");
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("查找标注 @Super 所有的 User 集合对象:" + users);
}
  • xml文件中写primary字段区分,主bean和其他bean的区别
  • listableBeanFactory.getBeansWithAnnotation(Class);
    • 这个是返回的类型是Map<String,Object>类型,这块写Map<String, User>类似,是我们知道这个注解只标记在user pojo类型上面。

相关技术

解决依赖顺序,依赖继承问题:

<relativePath>../pom.xml</relativePath>

1
2
3
4
5
6
7
<parent>
<artifactId>thinking-in-spring</artifactId>
<groupId>com.thinking</groupId>
<version>1.0-SNAPSHOT</version>
<!-- 解决依赖顺序,依赖继承问题 -->
<relativePath>../pom.xml</relativePath>
</parent>

Spring ioc 依赖注入

依赖注入和依赖查找不是来自同一个来源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<!-- 复用 -->
<import resource="Dependency-lookup-context.xml"/>

<!-- 使用autowire 自动注入 -->
<bean id="userRepository" class="com.thinking.in.spring.ioc.repository.UserRepository" autowire="byType">

</bean>

</beans>
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
public class UserRepository {

private Collection<User> users;

private BeanFactory beanFactory;

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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    // 配置xml配置文件
// 启动Spring 加载上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/Dependency-injection-context.xml");

// 自定义bean
UserRepository userRepository = beanFactory.getBean(UserRepository.class);
// 内建依赖bean对象
System.out.println(userRepository.getBeanFactory());
// 系统自建的bean
Environment environment = beanFactory.getBean(Environment.class);
// false
System.out.println(beanFactory == userRepository.getBeanFactory());


userRepository.getBeanFactory()获取的出来bean是org.springframework.beans.factory.support.DefaultListableBeanFactory对象。

beanFactory获取出来的bean 是org.springframework.context.support.ClassPathXmlApplicationContext对象。

Spring IOC 依赖来源

  • 自定义bean
  • 内建依赖bean对象
  • 容器内建依赖

Spring ioc 配置元信息

bean自定义配置

  • 基于XML文件
  • 基于properties文件
  • 基于Java注解
  • 基于Java api

ioc容器配置

  • 基于XML文件
  • 基于Java注解
  • 基于Java api

外部化属性配置

  • 基于Java注解

beanFaction和ApplicationContext谁才是Spring ioc容器?

application就是beanFactory,application就是beanFaction的子接口。beanFaction是一个底层基本的ioc容器,然而application是beanFaction的一个超集。

ClassPathXmlApplicationContext

​ <- AbstractXmlApplicationContext

​ <-AbstractRefreshableConfigApplicationContext

​ <-AbstractRefreshableApplicationContext

​ <-AbstractApplicationContext

​ <-ConfigurableApplicationContext

​ <-ApplicationContext

​ <-BeanFactory

如果想使用beanFactory,需要通过org.springframework.context.support.AbstractRefreshableApplicationContext#getBeanFactory获取底层beanFactory。

选用beanFactory还是Application?

beanFactory方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class BeanFactoryAsIocContainerDemo {

public static void main(String[] args) {
// 创建beanFactory 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// XML 配置文件 ClassPath 路径
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);
}
}
}

无需处理复杂操作,直接加载bean 就可以。

application
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
public class AnnotationApplicationContextAsIocContainerDemo {

public static void main(String[] args) {

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 AnnotationApplicationContextAsIocContainerDemo 设置成配置类
applicationContext.register(AnnotationApplicationContextAsIocContainerDemo.class);
// 不添加 出现has not been refreshed yet
applicationContext.refresh();
// 依赖查找集合对象
lookupCollectionByType(applicationContext);
}

@Bean
public User user(){
User user = new User();
user.setId("1");
user.setName("test");
return 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);
}
}
}

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
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
64
65
public void refresh() throws BeansException, IllegalStateException {
// 需要加把锁,只有一个线程才能执行操作,bean的刷新
synchronized (this.startupShutdownMonitor) {
// bean创建前的处理
// Prepare this context for refreshing.
prepareRefresh();
// 刷新或者创建bean处理
// 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.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}