A. spring 普通类 怎么注入bean
spring在普通类中注入bean实例 或注入静态变量的bean Spring的注入有一个问题就是普通类没有办法获得Bean文件中的bean实例。这就是如果是在Web的Servlet环境中可以通过WebApplicationContextUtils,如果是普通类就不好处理了。这需要一点设计的技巧。下面是一个静态类使用Bean文件中实例的例子1、如果是在配置文件中配置来注入:public class UserinfoUtil{ private IUserInfo userInfo; private static UserinfoUtil info; public void setUserInfo(IUserInfo userInfo) { this.userInfo = userInfo; } public void init() { info = this; info.userInfo = this.userInfo; } public static int addUserLoginCnt(String phonenumber) { return info.userInfo.addUserLoginCnt(phonenumber); }} 相应的bean的配置:相应的Bean文件的配置 <bean id="userinfoUtil" class="com.huawei.aimi.webportal.service.UserinfoUtil" init-method="init"> <property name="userInfo" ref="userInfo"/> </bean>2、用注解的方式注入:public class UserinfoUtil{ @Autowired private IUserInfo userInfo; private static UserinfoUtil info; public void setUserInfo(IUserInfo userInfo) { this.userInfo = userInfo; } @PostConstruct public void init() { info = this; info.userInfo = this.userInfo; } public static int addUserLoginCnt(String phonenumber) { return info.userInfo.addUserLoginCnt(phonenumber); }}
B. Spring中读取bean配置文件的几种方式
BeanFactory允许InputStream作为构造函数的参数,也可以org.springframework.core.io.Resource接口。下面这个例子是用ClassPathResource作为参数:Resource resource = new ClassPathResource("bean.xml");BeanFactory factory = new XmlBeanFactory(resource);ActionBean action = (ActionBean) factory.getBean("actionBean"); 如果同一个Bean在配置文件有多个bean的定义,则用下面的方法取得所有的对象:Resource resource = new ClassPathResource("bean.xml");ListableBeanFactory factory = new XmlBeanFactory(resource);Map helloBeans = factory.getBeansOfType(ActionBean.class, false, false);
C. 怎样加载多个Spring bean 配置文件
对于大多数的应用,从表现层的action,到持久层的DataSource,都被Spring 作为bean 管理。如果这些bean 被配置在同一个文件中,阅读及维护该配置文件将是一件非常有挑战的事情。因此, Spring 建议:将一个大的配置文件分解成多个小的配置文件,使每个配置文件仅仅管理功能近似于bean; 这样不仅可以分散配置文件,降低修改配置文件的风险,而且更符合"分而治之"的软件工程原理。多个配置文件最终需要汇总, ApplicationContext提供如下方式来汇总多个配置文件:.使用App1icationContext 加载多个配置文件。• Web 应用启动时加载多个配置文件。• XML 配置文件中导入其他配置。1 ApplicationContext 加载多个配置文件 ApplicatonContext 的常用实现类有如下两个:• ClassPathXm1 ApplicationContext 。• 。这两个类都可以用来加载多个配置文件,它们的构造器都可以接收一个数组,并在该数组中存放多个配置文件。 可采用如下代码加载多个配置文件:/I创建配置文件数组/I假设有3 个配置文件: a.xml , b.xml , c.xmlStr工ng[) configLocations = {"a.xml" , "b.xml" , "c.xml"}以配置文件数组为参数,创建ApplicationContextApplicationContext ctx = new (configLocations);与采用创建ApplicationContext的方式相似,区别仅在于二者搜索配置文件的路径不同:通过CLASSPATH路径搜索配置文件:而则在当前路径搜索配置文件。2 Web 应用启动时加载多个配置文件 参看5.12.3 节所述,通过ContextLoaderListener 也可加载多个配置文件,可利用337轻量级J2EE 企业应用实战一一-Struts+Spring+Hibernate 整合开发<context-pararn>元素来指定多个配置文件位置,其配置如下:<l– 确定配置文件的位置一〉<context-param><param-name>contextConfigLocation</param-name><1– 此处可以列出多个Spring 的XML 配置文件><param-value>/WEB-INF/Context.xml IWEB-INF/applicationContext.xml<1param-value><context-param>3 XML 配置文件中导人其他配置文件 配置文件本身和其子元素import. 可用于导入其他配置文件。具体的配置示例如下:<?xml version="1.0" encod工口g="gb2312"?><!一指定Spring 配置文件的dtd><!DOCTYPE beans PUBLIC "-IISPR工NGIIDTD BEANIIEN"''htt p:/ /ww w.springframe work.o rg/dtd/spring-beans.dtd''><!– Spring 配置文件的根元素-><beans><!一导入第→份配置文件: serv工ces.xml一〉<import resource="serv工ces.xml"l><!– 导入第二份配置文件: resources/messageSource.xml 一〉<import resource="resources/messageSource.xml"l><!– 导入第二份配置文件: resourcesl themeSource.xml –><import resource="/resources/themeSource.xml"l><!– 下面定义该文件垦的其他bean…〉<bean id="beanl" class=". .."1><bean id="bea口2" class="…"I></beans>
D. spring配置文件中能够用到的bean的作用域都有哪些
singleton作用域:当把一个bean定义设置为singleton作用域是,springioc容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回该bean的同一实例。值得强调的是singleton作用域是spring中的缺省作用域。prototype作用域:prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getbean()方法)时都会创建一个新的bean实例。根据经验,对有状态的bean应使用prototype作用域,而对无状态的bean则应该使用singleton作用域。对于具有prototype作用域的bean,有一点很重要,即spring不能对该bean的整个生命周期负责。具有prototype作用域的bean创建后交由调用者负责销毁对象回收资源。简单的说:singleton只有一个实例,也即是单例模式。prototype访问一次创建一个实例,相当于new。应用场合:1.需要回收重要资源(数据库连接等)的事宜配置为singleton,如果配置为prototype需要应用确保资源正常回收。2.有状态的bean配置成singleton会引发未知问题,可以考虑配置为prototype。
E. spring 怎样管理bean
BeanFactory采用了工厂设计模式,负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。而ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:国际化支持、aop、事务等。同时BeanFactory在解析配置文件时并不会初始化对象,只有在使用对象getBean()才会对该对象进行初始化,而ApplicationContext在解析配置文件时对配置文件中的所有对象都初始化了,getBean()方法只是获取对象的过程。
因此我们一般在使用的时候尽量使用ApplicationContext。
ApplicationContext是如何管理Bean呢?下面这个Demo简单模仿了这个原理:
1.建立一个类PersonServiceBean,并在xml文件中进行配置。
[java]view plain
{
publicvoidsave(){
System.out.println("我是save()方法");
}
}
[html]view plain
<beanid="personService"class="cn.itcast.service.impl.PersonServiceBean"></bean>
2.建立类BeanDefinition,提供一个构造函数,将其作为每个bean的公共转型类。
[java]view plain
publicclassBeanDefinition{
privateStringid;
privateStringclassName;
publicBeanDefinition(Stringid,StringclassName){
this.id=id;
this.className=className;
}
publicStringgetId(){
returnid;
}
publicvoidsetId(Stringid){
this.id=id;
}
publicStringgetClassName(){
returnclassName;
}
publicvoidsetClassName(StringclassName){
this.className=className;
}
}
3.建立容器类tgbApplicationContext。[java]view plain
/**
*测试spring容器
*@authorhegang
*
*/
{
privateList<BeanDefinition>beanDefines=newArrayList<BeanDefinition>();
privateMap<String,Object>sigletons=newHashMap<String,Object>();
(Stringfilename){
this.readXML(filename);
this.instanceBeans();
}
/**
*完成bean的实例化
*/
privatevoidinstanceBeans(){
for(BeanDefinitionbeanDefinition:beanDefines){
try{
if(beanDefinition.getClassName()!=null&&!"".equals(beanDefinition.getClassName().trim())){
sigletons.put(beanDefinition.getId(),Class.forName(beanDefinition.getClassName()).newInstance());
}
}catch(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
/**
*读取xml配置文件
*@paramfilename
*/
privatevoidreadXML(Stringfilename){
SAXReadersaxReader=newSAXReader();//创建读取器
Documentdocument=null;
try{
URLxmlpath=this.getClass().getClassLoader().getResource(filename);
document=saxReader.read(xmlpath);
Map<String,String>nsMap=newHashMap<String,String>();
nsMap.put("ns","http://www.springframework.org/schema/beans");//加入命名空间
XPathxsub=document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径
xsub.setNamespaceURIs(nsMap);//设置命名空间
List<Element>beans=xsub.selectNodes(document);//获取文档下所有的bean节点
for(Elementelement:beans){
Stringid=element.attributeValue("id");//获取id属性值
Stringclazz=element.attributeValue("class");//获取class属性值
BeanDefinitionbeanDefine=newBeanDefinition(id,clazz);
beanDefines.add(beanDefine);
}
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*获取bean实例
*@parambeanName
*@return
*/
publicObjectgetBean(StringbeanName){
returnthis.sigletons.get(beanName);
}
}
该类中拥有一个List<BeanDefinition>泛型集合类以及一个Map<String,Object>集合。通过查看代码我们知道这个容器类所做的事情如下:
a.读取配置文件bean.xml,并根据文件中bean的id,class属性实例化一个BeanDefinition,装入泛型集合中。
b.通过循环+反射,将List<BeanDefinition>中的bean加入到Map<String,Object>中,这里用反射将bean中的className属性转换为一个实例化的bean对象加入到了Map中。
c.提供一个对外的接口,通过传入参数获取该bean。
4.下面就是通过容器类获取具体bean的代码了。
[java]view plain
publicclassSpringTest{
@Test
publicvoidinstanceSpring(){
=("beans.xml");
PersonServicepersonService=(PersonService)ctx.getBean("personService");
personService.save();
}
}
通过调用save()方法可以调到PersonServiceBean中去。
通过这样的Demo,可以清楚看到Spring容器做的事情。它在初始化的时候将配置文件中bean以及相对应关系的配置都加入到ApplicationContext,通过一系列的转换将这些bean实例化,bean被它进行了管理,所以ApplicationContext就扮演了一个容器的角色。
F. Java Spring可以有多个beans.xml文件吗如果可以怎样+struts来配置
可以,你在Struts的配置中这样写就可以了:<plug-inclassName="org.springframework.web.struts.ContextLoaderPlugIn"><set-propertyproperty="contextConfigLocation"value="/WEB-INF/applicationContext1.xml,/WEB-INF/applicationContext2.xml,/WEB-INF/applicationContext3.xml"/></plug-in>只要用“,”隔开就可以了,可以有多个
G. spring 配置文件的bean自动注入失败的解决方法是什么
一个Spring注入问题,首先看一个普通Spring Bean,
publicclassFoo{@AutowiredBarbar;publicvoiddoSomething(){bar.doSomething();}}
Spring配置一:
<beanid="bar"class="com.test.Bar"></bean><beanid="foo"class="com.test.Foo"></bean>
单元测试:
@Testpublicvoidtest_doSomthing(){ApplicationContextctx=("applicationContext-test.xml");Foofoo=ctx.getBean(Foo.class);foo.doSomething();}
执行上述测试方法,报错
java.lang.NullPointerExceptionatcom.test.Foo.doSomething(Foo.java:15)atcom.test.FooTest.test_doSomthing(FooTest.java:13)
即foo bean中的bar并未注入。
Spring配置二:
<context:component-scanbase-package="com.test"></context:component-scan>
当改成配置二后执行上述单元测试方法便能成功通过。经分析日志及查看源代码,发现使用配置二时供装载了6个bean,如下所示:
DEBUGorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216)[applicationContext-test.xml]DEBUGorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530)[email protected]:org.s[email protected]14cc51c8:definingbeans[bar,foo,org.springframework.context.annotation.,org.springframework.context.annotation.,org.springframework.context.annotation.,org.springframework.context.annotation.];rootoffactoryhierarchy
而使用配置一时只有两个bean,如下所示:
DEBUGorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216)[applicationContext-test.xml]DEBUGorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530)[email protected]:org.s[email protected]18481697:definingbeans[bar,foo];rootoffactoryhierarchy
配置二执行单元测试通过的原因似乎就在于多出的这几个bean。是不是只要有context:component-scan元素在自动就会有这几个bean的产生?验证此假设
在配置一中添加一个无实际意义的context:component-scan元素,如下所示:
<context:component-scanbase-package="com.nonexist"></context:component-scan>
这时执行单元测试能通过,同配置二一样也会装载6个bean。那么这6个bean中到底哪个对注入bar到Foo中起了作用呢?
经过断点调试发现是 bean起了作用,见输出日志:
2015-04-2520:23:09DEBUGorg.springframework.beans.factory.annotation.InjectionMetadata.<init>(InjectionMetadata.java:60)Foundinjectedelementonclass[com.test.Foo]:AutowiredFieldElementforcom.test.Barcom.test.Foo.bar2015-04-2520:23:09DEBUGorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:85)'foo':AutowiredFieldElementforcom.test.Barcom.test.Foo.bar2015-04-2520:23:09DEBUGorg.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245)'bar'2015-04-2520:23:09DEBUGorg.springframework.beans.factory.annotation..registerDependentBeans(.java:424)Autowiringbytypefrombeanname'foo'tobeannamed'bar'2015-04-2520:23:09DEBUGorg.springframework.beans.factory.support..createBean(.java:458)'foo'
那么直接在配置一种显式添加bean呢?如下所示:
<beanid="bar"class="com.tcl.account.service.test.Bar"></bean><beanid="foo"class="com.tcl.account.service.test.Foo"></bean><beanid=""class="org.springframework.beans.factory.annotation."></bean>
测试会不会通过?会通过。见日志:
DEBUGorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216)[applicationContext-test.xml]DEBUGorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530)[email protected]:org.s[email protected]1924ed52:definingbeans[bar,foo,];rootoffactoryhierarchyDEBUGorg.springframework.beans.factory.annotation.InjectionMetadata.<init>(InjectionMetadata.java:60)Foundinjectedelementonclass[com.test.Foo]:AutowiredFieldElementforcom.test.Barcom.test.Foo.barDEBUGorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:85)'foo':AutowiredFieldElementforcom.test.Barcom.test.Foo.barDEBUGorg.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245)'bar'DEBUGorg.springframework.beans.factory.annotation..registerDependentBeans(.java:424)Autowiringbytypefrombeanname'foo'tobeannamed'bar'DEBUGorg.springframework.beans.factory.support..createBean(.java:458)'foo'
那么为什么在配置文件中添加了context:componet-scan元素后就会自动添加那另外4个bean呢?经过断点调试发现Spring隐式装载的4个bean是在如下方法中加载的:
Set<BeanDefinitionHolder>org.springframework.context.annotation.AnnotationConfigUtils.(,Objectsource)
其调用链如下所示:
补充一:
若仍用配置一,但单元测试改成如下形式也可以测试通过。
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations={"classpath:/applicationContext-test.xml"})publicclassFooTest2{@AutowiredprivateFoofoo;@Testpublicvoidtest_doSomthing(){foo.doSomething();}}
当然一点都不意外,这种方式也会隐式加载那4个bean,见日志:
DEBUGorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216)[classpath:/applicationContext-test.xml]INFOorg.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:500)Refreshi[email protected]51f3336e:startupdate[SunApr2617:27:35CST2015];rootofcontexthierarchyDEBUGorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530)Beanfactoryf[email protected]51f3336e:org.s[email protected]4f9d1352:definingbeans[bar,foo,org.springframework.context.annotation.,org.springframework.context.annotation.,org.springframework.context.annotation.,org.springframework.context.annotation.];rootoffactoryhierarchy
补充二,若使用的是@Value,效果同@Autowired,即也需要隐式加载 bean。
publicclassFoo{@Value("${bar}")Stringbar;publicvoiddoSomething(){System.out.println(bar);}}
补充三:
若使用配置一,@PostConstruct标注的方法也不会被执行,但此时需要隐式加载的Spring bean是:org.springframework.context.annotation.
补充四:
在配置一中添加如下配置
<context:annotation-config/>
也会隐式加载那4个bean
H. bean>和<bean>的区别
就像身份证号和人名的区别,每个bean的id(身份证号)都不同,但可以有相同的name (人名)。id属性命名必须满足XML的命名规范,因为id其实是XML中就做了限定的。name属性则没有这些限定,你可以使用几乎任何的名称。配置文件中不允许出现两个id相同的<bean>,否则在初始化时即会报错。配置文件中允许出现两个name相同的<bean>。
I. 十六、配置文件 十七、如何取得Spring管理的bean
十六、关于写几个配置文件的说明我看到有的人把配置文件写两份:一个是原有的applicationContext.xml,这个文件从spring2.0-2.5时一直在使用。别一个是新加的spring MVC的配置文件。其实这两个文件是可以写成一个文件的,springMVC相关的配置,数据源,事务相关配置可以都写再一个配置文件中。本例子中只使用了一个spring配置文件叫“springMVC.xml”。就不要再多配置一个applicationContext.xml文件了。web.xml文件中也不要再配置org.springframework.web.context.ContextLoaderListener的listener了。写两个配置文件一般就会导致扫描两次,一定要精确控制扫描的包名,做到不重复扫描。1、servlet方式加载时,【web.xml】springMVCorg.springframework.web.servlet.*:/springMVC.xml1spring容器放在ServletContext中的key是org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC注意后面的springMVC,是你的servlet-name配置的值,注意适时修改。ServletContext sc=略 WebApplicationContext attr = (WebApplicationContext)sc.getAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC"); 2、listener方式加载时:【web.xml】contextConfigLocation/WEB-INF/applicationContextorg.springframework.web.context.ContextLoaderListener【jsp/servlet】可以这样取得ServletContext context = getServletContext(); WebApplicationContext applicationContext = WebApplicationContextUtils .getWebApplicationContext(context); 3、通用的方法来了,神器啊,前的 1、2两种方法并不通用,可以抛弃了。在配置文件中加入:import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /*** 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.* */publicclass SpringContextHolder implements ApplicationContextAware { privatestatic ApplicationContext applicationContext; /*** 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.*/publicvoid setApplicationContext(ApplicationContext applicationContext) { SpringContextHolder.applicationContext = applicationContext; // NOSONAR} /*** 取得存储在静态变量中的ApplicationContext.*/publicstatic ApplicationContext getApplicationContext() { checkApplicationContext(); return applicationContext; } /*** 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.*/@SuppressWarnings("unchecked") publicstatic T getBean(String name) { checkApplicationContext(); return (T) applicationContext.getBean(name); } /*** 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.*/@SuppressWarnings("unchecked") publicstatic T getBean(Class clazz) { checkApplicationContext(); return (T) applicationContext.getBeansOfType(clazz); } /*** 清除applicationContext静态变量.*/publicstaticvoid cleanApplicationContext() { applicationContext = null; } privatestaticvoid checkApplicationContext() { if (applicationContext == null) { thrownew IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder"); } } }