社区精选|Spring 中的父子容器是咋回事?
SegmentFault
共 17883字,需浏览 36分钟
·
2023-07-29 00:13
今天小编为大家带来的是社区作者 江南一点雨 的文章,让我们一起来学习Spring 中的父子容器。
父子容器
为什么需要父子容器
问题呈现
├── admin
│ ├── pom.xml
│ └── src
│ ├── main
│ │ ├── java
│ │ └── resources
├── consumer
│ ├── pom.xml
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ └── javaboy
│ │ │ └── consumer
│ │ │ └── RoleService.java
│ │ └── resources
│ │ └── consumer_beans.xml
├── merchant
│ ├── pom.xml
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ └── javaboy
│ │ │ └── merchant
│ │ │ └── RoleService.java
│ │ └── resources
│ │ └── merchant_beans.xml
└── pom.xml
public class RoleService {
public String hello() {
return "hello consumer";
}
}
public class RoleService {
public String hello() {
return "hello merchant";
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.javaboy.consumer.RoleService" id="roleService"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.javaboy.merchant.RoleService" id="roleService"/>
</beans>
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
ctx.setConfigLocations("consumer_beans.xml", "merchant_beans.xml");
ctx.refresh();
org.javaboy.merchant.RoleService rs1 = ctx.getBean(org.javaboy.merchant.RoleService.class);
org.javaboy.consumer.RoleService rs2 = ctx.getBean(org.javaboy.consumer.RoleService.class);
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
ctx.setConfigLocations("consumer_beans.xml", "merchant_beans.xml");
ctx.setAllowBeanDefinitionOverriding(false);
ctx.refresh();
父子容器
兄弟关系
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
ClassPathXmlApplicationContext child1 = new ClassPathXmlApplicationContext("consumer_beans.xml");
ClassPathXmlApplicationContext child2 = new ClassPathXmlApplicationContext("merchant_beans.xml");
child1.setParent(ctx);
child2.setParent(ctx);
ctx.setAllowBeanDefinitionOverriding(false);
ctx.refresh();
org.javaboy.consumer.RoleService rs1 = child1.getBean(org.javaboy.consumer.RoleService.class);
org.javaboy.merchant.RoleService rs2 = child2.getBean(org.javaboy.merchant.RoleService.class);
System.out.println("rs1.hello() = " + rs1.hello());
System.out.println("rs2.hello() = " + rs2.hello());
父子关系
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("consumer_beans.xml");
ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext("merchant_beans.xml");
child.setParent(parent);
child.refresh();
org.javaboy.consumer.RoleService rs1 = parent.getBean(org.javaboy.consumer.RoleService.class);
org.javaboy.merchant.RoleService rs2 = child.getBean(org.javaboy.merchant.RoleService.class);
org.javaboy.consumer.RoleService rs3 = child.getBean(org.javaboy.consumer.RoleService.class);
System.out.println("rs1.hello() = " + rs1.hello());
System.out.println("rs2.hello() = " + rs2.hello());
System.out.println("rs3.hello() = " + rs3.hello());
public interface HierarchicalBeanFactory extends BeanFactory {
/**
* Return the parent bean factory, or {@code null} if there is none.
*/
@Nullable
BeanFactory getParentBeanFactory();
/**
* Return whether the local bean factory contains a bean of the given name,
* ignoring beans defined in ancestor contexts.
* <p>This is an alternative to {@code containsBean}, ignoring a bean
* of the given name from an ancestor bean factory.
* @param name the name of the bean to query
* @return whether a bean with the given name is defined in the local factory
* @see BeanFactory#containsBean
*/
boolean containsLocalBean(String name);
}
特殊情况
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("consumer_beans.xml");
ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext("merchant_beans.xml");
child.setParent(parent);
child.refresh();
String[] names1 = child.getBeanNamesForType(org.javaboy.merchant.RoleService.class);
String[] names2 = child.getBeanNamesForType(org.javaboy.consumer.RoleService.class);
System.out.println("names1 = " + Arrays.toString(names1));
System.out.println("names2 = " + Arrays.toString(names2));
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("consumer_beans.xml");
ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext();
child.setParent(parent);
child.refresh();
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(child, org.javaboy.consumer.RoleService.class);
for (String name : names) {
System.out.println("name = " + name);
}
Spring 和 SpringMVC
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext cwac && !cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
return wac;
}
-
方便管理,SpringMVC 主要处理控制层相关的 Bean,如 Controller、视图解析器、参数处理器等等,而 Spring 层则主要控制业务层相关的 Bean,如 Service、Mapper、数据源、事务、权限等等相关的 Bean。 -
对于新手而言,两个容器分开配置,可以更好的理解 Controller、Service 以及 Dao 层的关系,也可以避免写出来在 Service 层注入 Controller 这种荒唐代码。
3. 小结
往期推荐
社区精选|如何方便的检测React项目的性能?
社区精选|一道经典面试题:BeanFactory 和 FactoryBean 有何区别?
社区精选|深入了解 CSS 颜色混合函数 color-mix
评论