
在配置文件中加入:
Xml代码
<!-- 用于持有ApplicationContext,可以使用SpringContextHoldergetBean('xxxx')的静态方法得到spring bean对象 -->
<bean class="comxxxxxSpringContextHolder" lazy-init="false" />
Java代码
import orgspringframeworkcontextApplicationContext;
import orgspringframeworkcontextApplicationContextAware;
/
以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext
/
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/
实现ApplicationContextAware接口的context注入函数, 将其存入静态变量
/
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolderapplicationContext = applicationContext; // NOSONAR
}
/
取得存储在静态变量中的ApplicationContext
/
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/
从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型
/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContextgetBean(name);
}
/
从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型
/
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<T> clazz) {
checkApplicationContext();
return (T) applicationContextgetBeansOfType(clazz);
}
/
清除applicationContext静态变量
/
public static void cleanApplicationContext() {
applicationContext = null;
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext未注入,请在applicationContextxml中定义SpringContextHolder");
}
}
}
1、servlet方式加载时,
webxml
Xml代码
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>orgspringframeworkwebservletDispatcherServlet</servlet-class>
<init-param>
<param-name>contExtConfigLocation</param-name>
<param-value>classpath:/springMVCxml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
spring容器放在ServletContext中的key是orgspringframeworkwebservletFrameworkServletCONTEXTspringMVC
注意后面的springMVC,是你的servlet-name配置的值,注意适时修改。
Java代码
ServletContext sc=略
WebApplicationContext attr = (WebApplicationContext)scgetAttribute("orgspringframeworkwebservletFrameworkServletCONTEXTspringMVC");
2、listener方式加载时:
webxml
Xml代码
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext</param-value>
</context-param>
<listener>
<listener-class>orgspringframeworkwebcontextContextLoaderListener</listener-class>
</listener>
jsp/servlet可以这样取得
Java代码
ServletContext context = getServletContext();
WebApplicationContext applicationContext = WebApplicationContextUtils getWebApplicationContext(context);
3、通用的方法来了,神器啊,前的 1、2两种方法并不通用,可以抛弃了。
在配置文件中加入:
Xml代码
<!-- 用于持有ApplicationContext,可以使用SpringContextHoldergetBean('xxxx')的静态方法得到spring bean对象 -->
<bean class="comxxxxxSpringContextHolder" lazy-init="false" />
Java代码
import orgspringframeworkcontextApplicationContext;
import orgspringframeworkcontextApplicationContextAware;
/
以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext
/
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/
实现ApplicationContextAware接口的context注入函数, 将其存入静态变量
/
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolderapplicationContext = applicationContext; // NOSONAR
}
/
取得存储在静态变量中的ApplicationContext
/
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/
从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型
/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContextgetBean(name);
}
/
从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型
/
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<T> clazz) {
checkApplicationContext();
return (T) applicationContextgetBeansOfType(clazz);
}
/
清除applicationContext静态变量
/
public static void cleanApplicationContext() {
applicationContext = null;
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext未注入,请在applicationContextxml中定义SpringContextHolder");
}
}
}
你需要我,我需要你就是循环依赖
在Spring中使用的三级缓存来解决循环依赖问题,这里的缓存其实就是Map对象
当获取一个Bean时会先从缓存中查找是否有相应的Bean。
1 创建A实例
2 将A实例(半初始化,属性没有填充)暴露放入缓存中
3 填充A实例的属性
4 A实例属性依赖B对象
5 创建B对象实例
6 填充B实例属性
7 B实例属性依赖A对象
8 将上面已经暴露到三级缓存中的A对象注入给B实例
在获取A对象的时候执行上面271中的getSingleton方法,会将三级缓存中A这个半初始化状态的对象移除,将其存入到二级缓存中。
9 B实例Bean的创建工作继续执行初始化方法
B如果需要AOP代理?最终B对象是个代理对象。B到此就完全的初始化完了,B的依赖对象A此时是个半初始化状态的对象
10 B实例对象保存到一级缓存
最终B实例创建,初始化都执行完后会将自身加入到一级缓存同时清除二级,三级缓存
11 A实例Bean创建继续执行
如果B是被AOP代理的那么此时的A实例注入的B对象就是一个代理对象。
12 A实例Bean执行初始化方法
13 A继续执行上面的10步骤
三级缓存解决问题:循环依赖+AOP问题
只用一,二级缓存:
从上面罗列的步骤看似乎很是完美解决了循环依赖问题,接下来我们看看加入AOP的场景
假如A,B两个对象最终都是要被AOP代理的
执行到这里,A中依赖的B是代理对象没有问题,但是B中依赖的A对象是原始对象;这就不正确了应该依赖的A也必须是代理对象才是。
引入三级缓存:
三级缓存引入了ObjectFactory对象,在获取对象的时候,是调用ObjectFactory#getObject方法。
而这个getObject方法的实现实际执行的是getEarlyBeanReference方法,再来回顾下:
在创建实例时先将其存入三级缓存中:
getEarlyBeanReference方法就是提前创建代理对象
如果开启了AOP代理后
通过getEarlyBeanReference方法提前创建代理对象。这样就解决了循环依赖时AOP代理问题。保证获取的都是同一个对象。
其实引入三级缓存还解决了一个问题就是延迟代理对象的创建,如果不应用ObjectFactory方式那么我们需要不管需不需要都要先创建代理对象,而引入ObjectFactory可以在注入的时候先暴露的是ObjectFactory只有在调用getObject方法的时候才去创建真正的代理对象(避免了所有Bean都强制创建代理对象)。当没有被代理时可以直接返回原始对象,如果被代理会提前创建代理对象。
不用二级直接是用一,三级缓存?
假设场景:A 依赖 B,B 依赖 A、C,C 依赖 A
如果这样会出现不同的代理对象,每次调用getObject都会创建不同的代理对象(在上面的场景中如果只用一,三级缓存那么 B 依赖 A会通过getObject获取一个代理对象Proxy$1,接着注入C的时候 C中又依赖A,那这时候又从getObject获取对象那么返回的将又会是一个新的代理对象Proxy$2;在这个过程中A对象就出现了2个不一样的对象了,这肯定是错误的)。而引入二级缓存也就解决了这个问题。只有二级缓存没有的时候才从三级缓存汇总获取(如果需要则创建代理对象,然后保存到二级缓存中,二级缓存中已经是提前创建了代理对象(如果需要代理))。
当一个Bean完全的创建完以后放入一级缓存中,此时会吧二级三级中的缓存清除。
完毕!!!!
SpringMVC参数统一验证方法
SpringBoot多数据源配置详解
SpringCloud Nacos 整合feign
Spring AOP动态代理失效的解决方法@Transactional为何会失效
SpringBoot配置文件你了解多少?
SpringBoot邮件发送示例 Springboot面试题整理附答案
SpringBoot项目查看线上日志
在Spring Cloud 中你还在使用Ribbon快来试试Load-Balancer
SpringBoot分库分表sharding-sphere3
在使用spring容器的web应用中,业务对象间的依赖关系都可以用spring-contextxml文件来配置,并且由spring容器来负责依赖对象的创建。如果要在servlet中使用spring容器管理业务对象,通常需要使用 WebApplicationContextUtilsgetRequiredWebApplicationContext(getServletContext()) 来获得WebApplicationContext,然后调用WebApplicationContextgetBean("beanName")来获得对象的引用,这实际上是使用了依赖查找来获得对象,并且在servlet代码中硬编码了应用对象的bean名字。
这种方式,相当于把spring容器中的bean加载到了servlet容器中,即把spring中的bean放到webxml的bean中。
以上就是关于如何取得Spring管理的bean全部的内容,包括:如何取得Spring管理的bean、如何获取spring bean、Spring是如何解决循环依赖的等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)