在spring bean 单例框架的ioc容器中对bean的配置上,以下哪个属性是非法的

Spring注入非单例bean以及scope的作用范围 - 寻找小包子 - ITeye技术网站
博客分类:
一、 问题描述
在大部分情况下,容器中的bean都是singleton类型的。
如果一个singleton bean要引用另外一个singleton bean,或者一个非singleton bean要引用另外一个非singleton bean时,通常情况下将一个bean定义为另一个bean的property值就可以了。不过对于具有不同生命周期的bean来说这样做就会有问题了,比如在调用一个singleton类型bean A的某个方法时,需要引用另一个非singleton(prototype)类型的bean B,对于bean A来说,容器只会创建一次,这样就没法在需要的时候每次让容器为bean A提供一个新的的bean B实例。
二、 解决方案
对于上面的问题Spring提供了三种解决方案:
放弃控制反转。
通过实现ApplicationContextAware接口让bean A能够感知bean 容器,并且在需要的时候通过使用getBean("B")方式向容器请求一个新的bean B实例。
Lookup方法注入。
Lookup方法注入利用了容器的覆盖受容器管理的bean方法的能力,从而返回指定名字的bean实例。
自定义方法的替代方案。
该注入能使用bean的另一个方法实现去替换自定义的方法。
三、 实现案例
3.1 放弃IOC
package learn.frame.spring.scope.
public interface Command {
public Object execute();
package learn.frame.spring.scope.
public class AsyncCommand implements Command {
public Object execute() {
ApplicationContextAware和BeanFactoryAware差不多,用法也差不多,实现了ApplicationContextAware接口的对象会拥有
一个ApplicationContext的引用,这样我们就可以已编程的方式操作ApplicationContext。看下面的例子。
public class CommandManager implements ApplicationContextAware {
//用于保存ApplicationContext的引用,set方式注入
private ApplicationContext applicationC
//模拟业务处理的方法
public Object process() {
Command command = createCommand();
return command.execute();
//获取一个命令
private Command createCommand() {
return (Command) this.applicationContext.getBean("asyncCommand"); //
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationC//获得该ApplicationContext引用
配置文件:beans-dropioc.xml
单例Bean commandManager的process()方法需要引用一个prototype(非单例)的bean,所以在调用process的时候先通过
createCommand方法从容器中取得一个Command,然后在执行业务计算。
scope="prototype"
&?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-3.0.xsd"&
&!-- 通过scope="prototype"界定该bean是多例的 --&
&bean id="asyncCommand" class="learn.frame.spring.scope.dropioc.AsyncCommand"
scope="prototype"&&/bean&
&bean id="commandManager" class="learn.frame.spring.mandManager"&
package org.shupeng.learn.frame.spring.
import java.util.ArrayL
import org.junit.B
import org.junit.T
import learn.frame.spring.mandM
import org.springframework.context.ApplicationC
import org.springframework.context.support.ClassPathXmlApplicationC
public class TestCommandManagerDropIOC {
private ApplicationC
public void setUp() throws Exception {
context = new ClassPathXmlApplicationContext("beans-dropioc.xml");
public void testProcess() {
CommandManager manager = (CommandManager) context.getBean("commandManager",
CommandManager.class);
System.out.println("第一执行process,Command的地址是:" + manager.process());
System.out.println("第二执行process,Command的地址是:" + manager.process());
Test结果:
第一执行process,Command的地址是:learn.frame.spring.scope.dropioc.AsyncCommand@187c55c
第二执行process,Command的地址是:learn.frame.spring.scope.dropioc.AsyncCommand@ae3364
通过控制台输出看到两次的输出借中的Command的地址是不一样的,因为我们为asyncCommand配置了scope="prototype"属性,这种方式就是使得每次从容器中取得的bean实例都不一样。
业务代码和Spring Framework产生了耦合。
3.2 Look方法注入
这种方式Spring已经为我们做了很大一部分工作,要做的就是bean配置和业务类。
新的业务:
package learn.frame.spring.scope.
import learn.frame.spring.
public abstract class CommandManager {
//模拟业务处理的方法
public Object process() {
Command command = createCommand();
return command.execute();
//获取一个命令
protected abstract Command createCommand();
配置文件:beans-lookup.xml
&?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-3.0.xsd"&
&!-- 通过scope="prototype"界定该bean是多例的 --&
&bean id="asyncCommand" class="learn.frame.spring.scope.dropioc.AsyncCommand"
scope="prototype"&&/bean&
&bean id="commandManager" class="learn.frame.spring.mandManager"&
&lookup-method name="createCommand" bean="asyncCommand"/&
变化部分:
修改CommandManager类为abstract的,修改createCommand方法也为abstract的。
去掉ApplicationContextAware的实现及相关set方法和applicationContext变量定义
修改bean配置文件,在commandManager Bean中增加&lookup-method name="createCommand" bean="asyncCommand"/&。
package learn.frame.spring.
import org.junit.B
import org.junit.T
import learn.frame.spring.mandM
import org.springframework.context.ApplicationC
import org.springframework.context.support.ClassPathXmlApplicationC
public class TestCommandManagerLookup {
private ApplicationC
public void setUp() throws Exception {
context = new ClassPathXmlApplicationContext("beans-lookup.xml");
public void testProcess() {
CommandManager manager = (CommandManager) context.getBean("commandManager",
CommandManager.class);
System.out.println("第一执行process,Command的地址是:" + manager.process());
System.out.println("第二执行process,Command的地址是:" + manager.process());
测试结果:
第一执行process,Command的地址是:learn.frame.spring.scope.dropioc.AsyncCommand@5bb966
第二执行process,Command的地址是:learn.frame.spring.scope.dropioc.AsyncCommand@1e903d5
控制台打印出的两个Command的地址不一样,说明实现了。
&lookup-method&标签中的name属性就是commandManager Bean的获取Command实例(AsyncCommand)的方法,也就createCommand方法,bean属性是要返回哪种类型的Command的,这里是AsyncCommand。
&public|protected& [abstract] &return-type& theMethodName(no-arguments)
被注入方法不一定是抽象的,如果被注入方法是抽象的,动态生成的子类(这里就是动态生成的CommandManager的子类)会实现该方法。否则,动态生成的子类会覆盖类里的具体方法。
为了让这个动态子类得以正常工作,需要把CGLIB的jar文件放在classpath里,这就是我们引用cglib包的原因。
Spring容器要子类化的类(CommandManager)不能是final的,要覆盖的方法(createCommand)也不能是final的。
Lookup方法注入干净整洁,易于扩展,更符合Ioc规则,所以尽量采用这种方式。
四、 原理分析(bean的scope属性范围)
scope用来声明IOC容器中的对象应该处的限定场景或者说该对象的存活空间,即在IOC容器在对象进入相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象。
Spring容器最初提供了两种bean的scope类型:singleton和prototype,但发布2.0之后,又引入了另外三种scope类型,即request,session和global session类型。不过这三种类型有所限制,只能在web应用中使用,也就是说,只有在支持web应用的ApplicationContext中使用这三个scope才是合理的。
可以使用bean的singleton或scope属性来指定相应对象的scope,其中,scope属性只能在XSD格式的文档生命中使用,类似于如下代码所演示的形式:
&bean id ="mockObject1" class="..." singleton="false" /&
&bean id ="mockObject1" class="..."
scope="prototype" /&
注意:这里的singleton和设计模式里面的单例模式不一样,标记为singleton的bean是由容器来保证这种类型的bean在同一个容器内只存在一个共享实例,而单例模式则是保证在同一个Classloader中只存在一个这种类型的实例。
4.1. singleton
singleton类型的bean定义,在一个容器中只存在一个实例,所有对该类型bean的依赖都引用这一单一实例。singleton类型的bean定义,从容器启动,到他第一次被请求而实例化开始,只要容器不销毁或退出,该类型的bean的单一实例就会一直存活。
通常情况下,如果你不指定bean的scope,singleton便是容器默认的scope,所以,下面三种配置,形式实际上达成的是同样的效果:
DTD or XSD:
&bean id ="mockObject1" class="..." /&
&bean id ="mockObject1" class="..." singleton="true" /&
&bean id ="mockObject1" class="..."
scope="singleton" /&
4.2 prototype
scope为prototype的bean,容器在接受到该类型的对象的请求的时候,会每次都重新生成一个新的对象给请求方。
虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不在拥有当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回请求方该对象的一个新的实例之后,就由这个对象“自生自灭”了。
可以用以下方式定义prototype类型的bean:
&bean id ="mockObject1" class="..." singleton="false" /&
&bean id ="mockObject1" class="..."
scope="prototype" /&
4.3 request ,session和global session
这三个类型是spring2.0之后新增的,他们不像singleton和prototype那么通用,因为他们只适用于web程序,通常是和XmlWebApplicationContext共同使用。
&bean id ="requestPrecessor" class="...RequestPrecessor"
scope="request" /&
Spring容器,即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,该对象的生命周期即告结束。当同时有10个HTTP请求进来的时候,容器会分别针对这10个请求创建10个全新的RequestPrecessor实例,且他们相互之间互不干扰,从不是很严格的意义上说,request可以看做prototype的一种特例,除了场景更加具体之外,语意上差不多。
对于web应用来说,放到session中最普遍的就是用户的登录信息,对于这种放到session中的信息,我们我们可以使用如下形式的制定scope为session:
&bean id ="userPreferences" class="...UserPreferences"
scope="session" /&
Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,他比request scope的bean会存活更长的时间,其他的方面真是没什么区别。
global session:
&bean id ="userPreferences" class="...UserPreferences"
scope="globalsession" /&
global session只有应用在基于porlet的web应用程序中才有意义,他映射到porlet的global范围的session,如果普通的servlet的web 应用中使用了这个scope,容器会把它作为普通的session的scope对待。
(我只是听说过porlet这个词,好像是和servlet类似的一种java web技术,大家以后遇到的时候可以搜一下!)
五、 新的扩展(注解方式)
自Spring3.x开始,增加了@Async这样一个注解,Spring 文档里是这样说的:
The @Async annotation can be provided on a method so that invocation of that method will occur asynchronously. &/br&
In other words, the caller will return immediately upon invocation and the actual execution of the method will &/br&
occur in a task that has been submitted to a Spring TaskExecutor.
就是说让方法异步执行。
参考文档:
jiangshuiy
浏览: 115428 次
来自: 杭州
exec可能存在注入漏洞,如何控制安全问题啊?
面向对象涉及原则:1.开闭原则2.少用继承,多用聚合3.针对接 ...
jianyan163qq 写道好文章!我现在遇到一个调用的问题 ...
好文章!我现在遇到一个调用的问题:
我在Java程序里调用一 ...bean元素的id和name属性的区别&bean&元素的id属性和 name属性的区别 1. 一般情况下,一个Bean时,通过指定一个id属性作为Bean的名称.2.
id 属性在IoC容器中必须是唯一的3.
id 的命名要满足XML对ID属性命名规范:
必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号 4.
使用name属性,就可以使用很多特殊字符,早期在struts1 和 spring整合
&bean name="/login" class="....LoginAction" /&
name中含有/ ,使用id会报错5.
如果Bean的名称中含有特殊字符,就需要使用name属性例如:&bean name="#person" class="cn.itcast.bean.Person"/&6.
因为name属性可以相同,所以后出现Bean会覆盖之前出现的同名的Bean
xml的解析是从上到下的,所以先配置的bean会被加载到内存中,那么后配置的具有相同name的bean就会覆盖前面的.
如果bean元素没有id只有name ,name 属性值可以作为id 使用 ===============================================================================bean元素scope属性配置Bean的作用域&bean&元素scope属性,在spring规范中scope属性有五个取值: 1.
scope="singleton" 单例,在Spring IoC容器中仅存在一个Bean实例(默认的scope)
默认情况下:托管给spring默认在spring容器中只有一个Bean实例对象. 2.
scope="prototype" 多例,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new XxxBean() 3.
scope="request" 用于web,该作用域仅适用于WebApplicationContext环境.每次HTTP请求都会创建一个新的Bean,将Bean放入request范围,request.setAttribute("xxx"),在同一个request 获得同一个Bean 4.
scope="session" 用于web开发, 该作用域仅适用于WebApplicationContext环境.同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,将Bean 放入Session范围 5.
scope="globalSession"该作用域仅适用于WebApplicationContext环境.一般用于Porlet应用环境 , 分布式系统存在全局session概念,如果不是porlet环境,globalSession 等同于Session
Porlet是Servlet的一个升级,Porlet主要用于分布式系统.
在开发中主要使用 scope="singleton"、 scope="prototype" ===============================================================================
bean元素的init-method和destory-method属性
这两个属性只是bean生命周期中一部分内容,完成的Bean生命周期详见:本文档中Bean的生命周期 Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法。
&bean id=“foo” class=“...Foo”
init-method=“setup”
destory-method=“teardown”/&1.
init-method=“setup”用于指定:当bean被载入到容器的时候调用setup方法.
类似于Servlet的init()方法.2.
destory-method=“teardown”当bean从容器中删除的时候调用teardown.
类似于Serlvet的destory方法
注意destory-method属性只在scope= singleton有效3.
初始化方法和销毁方法一般都是无返回值,无参数的方法.4.
销毁方法必须关闭Spring容器才会被调用.即
ClassPathXmlApplicationContext applicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.close(); 5.web容器中会自动调用,但是main函数或测试用例需要手动调用Spring IOC/DI/注解-理论与实例并存 - coach - ITeye技术网站
博客分类:
一、定义:Spring 是一个开源的控制反转(Inversion of Control,IoC/DI)和面向切面(AOP)的容器框架,它的主要目的是简化企业开发
二、实例化Spring容器:
&&& 方法一:在类路径下寻找配置文件来实例化容器
ApplicationContext ctx =
new ClassPathXmlApplicationContext(new String[]{“beans.xml”});
&&& 方法二:在文件系统路径下寻找配置文件来实例化容器
ApplicationContext ctx =
new FileSystemXmlApplicationContext(new String[]{“d:""beans.xml”});
注:文件可指定多个
可建立单元测试来测试Spring容器的初始化
三、编写Spring 配置文件时,不能出现帮助信息的解决办法—添加schema文件
由于Spring的schema文件位于网络上,如果机器不能连接到网络,那么在写配置文件的时候就无法出现提示信息,解决办法有两种:
1. 让机器上网,Eclipse会自动从网络上下载schema文件并缓存在硬盘上
2.手动添加schema文件,方法如下:
windows-&preferences-&myeclipse-&files and editors-&xml-&xmlcatalog
a. 我们可以选择将schema文件放到User Specified Entries然后点击‘add’,在出现的窗口中的Key Type中选择URL, 在‘Location’中选择‘File System’,然后在Spring解压目录的dist/resources目录中选择spring-beans-2.5.xsd,
b. 回到设置窗口时候不要急于关闭窗口,应把窗口中的Key Type改为schema location,
c. key改为:
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
四、Spring 配置文件一个小插曲
&bean id=”” name=””&&/bean&,在这里,id 和name都是为这个bean取的名字,其实这两者意思相同,只是如果选择使用的是id,那么id命名则不能有特殊字符,如果使用的是name则可以使用特殊字符作为name。如
&bean id=”beanId” /& && &bean name=”bean-name”/&
五、Spring容器如何管理bean
首先读取beans.xml里的bean配置所有的id、class的值,作为String形式保存至对应一个Bean,形成bean列表
利用反射机制,将bean列表遍历,生成对象,如下:
package junit.
import java.net.URL;
import java.util.ArrayL
import java.util.HashM
import java.util.HashS
import java.util.L
import java.util.M
import org.dom4j.D
import org.dom4j.E
import org.dom4j.XP
import org.dom4j.io.SAXR
*传智传客版容器
publicclass ItcastClassPathXMLApplicationContext {
&&& private List&BeanDefinition& beanDefines = new ArrayList&BeanDefinition&();
&&& private Map&String, Object& sigletons = new HashMap&String, Object&();
&&& public ItcastClassPathXMLApplicationContext(String filename){
&&&&&&& this.readXML(filename);
&&&&&&& this.instanceBeans();
&&&& *完成bean的实例化
&&& privatevoid instanceBeans() {
&&&&&&& for(BeanDefinition beanDefinition : beanDefines){
&&&&&&&&&&& try {
&&&&&&&&&&&&&&& if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))
&&&&&&&&&&&&&&&&&&& sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
&&&&&&&&&&& } catch (Exception e) {
&&&&&&&&&&&&&&& e.printStackTrace();
&&&&&&&&&&& }
&&&& *读取xml配置文件
&&&& *@paramfilename
&&& privatevoid readXML(String filename) {
&&&&&&& SAXReader saxReader = new SAXReader();
&&&&&&& Document document =
&&&&&&& try {
&&&&&&&&&&& URL xmlpath = this.getClass().getClassLoader().getResource(filename);
&&&&&&&&&&& document = saxReader.read(xmlpath);
&&&&&&&&&&& Map&String, String& nsMap = new HashMap&String, String&();
&&&&&&&&&&& nsMap.put("ns", "http://www.springframework.org/schema/beans");// 加入命名空间
&&&&&&&&&&& XPath xsub = document.createXPath("//ns:beans/ns:bean");// 创建beans/bean查询路径
&&&&&&&&&&& xsub.setNamespaceURIs(nsMap);// 设置命名空间
&&&&&&&&&&& List&Element& beans = xsub.selectNodes(document);// 获取文档下所有bean节点
&&&&&&&&&&& for (Element element : beans) {
&&&&&&&&&&&&&&& String id = element.attributeValue("id");// 获取id属性值
&&&&&&&&&&&&&&& String clazz = element.attributeValue("class"); // 获取class属性值
&&&&&&&&&&&&&&& BeanDefinition beanDefine = new BeanDefinition(id, clazz);
&&&&&&&&&&&&&&& beanDefines.add(beanDefine);
&&&&&&&&&&& }
&&&&&&& } catch (Exception e) {
&&&&&&&&&&& e.printStackTrace();
&&&& *获取bean实例
&&&& *@parambeanName
&&&& *@return
&&& public Object getBean(String beanName){
&&&&&&& returnthis.sigletons.get(beanName);
六、Spring的三种实例化Bean方式
1.使用构造器实例化
&bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"&&/bean&
&&& 这种就是利用默认的构造器进行的实例化
2. 静态工厂方法实例化
&bean id="personService2" class="cn.itcast.service.impl.PersonServiceBeanFactory" factory-method="createPersonServiceBean"/&
3. 使用实例工厂方法实例化
&bean id="personServiceFactory" class="cn.itcast.service.impl.PersonServiceBeanFactory"/&
&bean id="personService3" factory-bean="personServiceFactory" factory-method="createPersonServiceBean2"/&
七、bean的作用域-属性scope
singleton:(默认)在每个Spring IOC容器中一个bean定义只有一个对象实例,默认情况下会在容器启动时初始化bean。但我们可以指定bean节点lazy-init=”true” 则表示不需要在容器初始化时候对bean进行初始化,只有在第一次getBean时候进行初始化,如果需要所有的bean都应用延迟初始化,可以在根节点&beans&设置default-lazy-init=”true”(不推荐,不利于观察bean初始化情况)
prototype:每次从容器中获取的bean都是新的对象
global session
七、Spring管理的bean的生命周期
默认情况下容器初始化的时候对bean进行实例化
如果scope为prototype时,在调用getBean方法时候对bean进行实例化
如果lazy-init为true时,容器初始化时候不会对bean进行实例化
综上所述,Spring管理的bean初始化点根据设定的条件不同而不同
init-method:在bean被实例化的后即会执行的方法
destroy-method:在bean被销毁的时候执行的方法(如果没有手动的销毁该bean,则只有在容器关闭的时候才会销毁)
正常的关闭Spring容器
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
ctx.close();
八、控制反转IoC 定义:
Public class PersonServiceBean {
Private PersonDao personDao = new PersonDaoBean();
Public void save (Person person) {
personDao.save(person);
PersonDaoBean是在应用内部创建和维护的,所谓的控制反转就是应用本身不负责依赖对象的创建和维护,依赖对象的创建及维护是由外部容器负责的,这样控制权就由应用转移到了外部容器,控制权的转移就是所谓的反转。
九、依赖注入(Dependency Injection)的定义:
当我们把依赖对象交给外部容器负责创建,那么PersonServiceBean类可以改成如下:
public class PersonServiceBean{
private PersonDao personD
//通过构造器参数,让容器把创建好的依赖对象注入进PersonServiceBean,当然也可以使用setter方法进行注入
public PersonServiceBean(PersonDao personDao) {
this.personDao = personD
Public void save(Person person) {
personDao.save(person);
所谓的依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中
十、依赖注入:
1.使用构造器注入
private PersonDao personD
&&& private S&&&
&&& public PersonServiceBean(PersonDao personDao, String name) {
&&&&&&& this.personDao = personD
&&&&&&& this.name =
beans.xml配置:
&bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"&
&constructor-arg index="0" type="cn.itcast.dao.PersonDao" ref=""&&/constructor-arg&
&&& &constructor-arg index="1" type="paramValue"&&/constructor-arg&
2.使用setter方法注入
ref形式注入:
&&& &bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"&
&&&&&&& &property name="personDao" ref="personDaoBean" /&
&&& &/bean&
可以采用内部bean方式进行注入,不同过ref方式的是,这种内部bean注入对于bean的重用性效果不好:
&&& &bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"&
&&&&&&& &property name="personDao"&
&&&&&&&&&&& &bean class="cn.itcast.dao.impl.PersonDaoBean" /&
&&&&&&& &/property&
&&& &/bean&
bean基本类型的注入:
&&& &bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"&
&&&&&&& &property name="personDao"&
&&&&&&&&&&& &bean class="cn.itcast.dao.impl.PersonDaoBean" /&
&&&&&&& &/property&
&&&&&&& &property name="name" value="itcast" /&
&&&&&&& &property name="id" value="100" /&
&&& &/bean&
集合类的注入:
&bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" &
&&&&&&& &property name="sets"&
&&&&&&&&&&& &set&
&&&&&&&&&&&&&&& &value&第一个&/value&
&&&&&&&&&&&&&&& &value&第二个&/value&
&&&&&&&&&&&&&&& &value&第三个&/value&
&&&&&&&&&&& &/set&
&&&&&&& &/property&
&&&&&&& &property name="lists"&
&&&&&&&&&&& &list&
&&&&&&&&&&&&&&& &value&第一个list元素&/value&
&&&&&&&&&&&&&&& &value&第二个list元素&/value&
&&&&&&&&&&&&&&& &value&第三个list元素&/value&
&&&&&&&&&&& &/list&
&&&&&&& &/property&
&&&&&&& &property name="properties"&
&&&&&&&&&&& &props&
&&&&&&&&&&&&&&& &prop key="key1"&value1&/prop&
&&&&&&&&&&&&&&& &prop key="key2"&value2&/prop&
&&&&&&&&&&&&&&& &prop key="key3"&value3&/prop&
&&&&&&&&&&& &/props&
&&&&&&& &/property&
&&&&&&& &property name="maps"&
&&&&&&&&&&& &map&
&&&&&&&&&&&&&&& &entry key="key-1" value="value-1" /&
&&&&&&&&&&&&&&& &entry key="key-2" value="value-2" /&
&&&&&&&&&&&&&&& &entry key="key-3" value="value-3" /&
&&&&&&&&&&& &/map&
&&&&&&& &/property&
3.使用Field注入(用于注解方式)
注入依赖对象,可以采用手工装配或者自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终装配的结果
1.&&&& 手工装配依赖对象
a)&&&&&& 在xml配置文件中,通过在bean节点下配置
b)&&&&&& 在java代码中使用@Autowired或@Resource注解方式进行装配。但我们需要在xml配置以下信息
&?xml version="1.0" encoding="UTF-8"?&
&beans xmlns="http://www.springframework.org/schema/beans"
&&&&&& xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
&&&&&& xmlns:context="http://www.springframework.org/schema/context"&&&&&&
&&&&&& xsi:schemaLocation="http://www.springframework.org/schema/beans&&&&&&&&&
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"&
&!-- 相当于启用解析注解的处理器 --&
&context:annotation-config/&
这个配置隐式注册了多个注释进行解析处理的处理器:
注解本身不做任何事情,只是利用这些处理器来达到配置一样的效果
AutowiredAnnotationBeanPostProcessor,
CommonAnnotationBeanPostProcesor,
PersistenceAnnotationBeanPostProcessor,
RquiredAnnotationBeanPostProcessor
注:@Resource注解在spring安装目录的lib/j2ee/common-annotations.jar
dist/spring.jar
lib/Jakarta-commons/commons-logging.jar
lib/aspectjaspectjweaver.jar、aspectjrt.jar//aop
lib/cglib/cglib-nodep-2.1_3.jar
lib/j2ee/common-annotations.jar
在java代码中使用@Autowired或@Resource注解方式进行装配,这两个注解的区别是:
@Autowired默认按类型装配,@Resource默认按照名称装配,当找不到与名称匹配的bean才会匹配的bean才会按类型装配
@Autowired
private PersonDao personD&&& //用于字段上
@Autowired
public void setOrderDao(OrderDao orderDao) {&&& //用于属性的setter方法上
&&& this.orderDao = orderD
@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false(默认是true),如果我们想按名称装配,可以结合@Qualifier注解一起使用,如下:
@Autowired @Qualifier(“personDaoBean”)
private PersonDao personD
如上面的注解,则@Autowired本身是按照类型装配,现在将会按名称装配
@Resource注解和@Actowired一样,也可以标注在字段或者属性的setter方法上,但他默认按照名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
@Resource(name=”personDaoBean”)
private PersonDao personD
注意:如果没有指定name属性,并且暗号默认的名称仍然找不到依赖对象时,“Resource注解会回退到按类型装配,但一旦指定了name属性,就只能按名称装配了
2.自动装配依赖对象
对于自动装配,作为了解
byType:按类型装配,可以根据属性的类型,在容器中寻找跟该类型匹配的bean。如果发现多个,那么将会抛出异常。如果没有找到,即属性值为null。
byName:按名称装配,可以根据属性的名称在容器中寻找跟该属性名相同的bean,如果没有找到,即属性值为null
constructor与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常
autodetect:通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式
十一、依赖注入的原理
在Spring容器管理bean原理的实例中进行改造,该例子涉及到两个实体类:BeanDefinition{id,class}、PropertyDefinition{name,ref}
package junit.
import java.beans.IntrospectionE
import java.beans.I
import java.beans.PropertyD
import java.lang.reflect.M
import java.net.URL;
import java.util.ArrayL
import java.util.HashM
import java.util.L
import java.util.M
import org.dom4j.D
import org.dom4j.E
import org.dom4j.XP
import org.dom4j.io.SAXR
*传智传客版容器
publicclass ItcastClassPathXMLApplicationContext {
&&& private List&BeanDefinition& beanDefines = new ArrayList&BeanDefinition&();
&&& private Map&String, Object& sigletons = new HashMap&String, Object&();
&&& public ItcastClassPathXMLApplicationContext(String filename){
&&&&&&& this.readXML(filename);
&&&&&&& this.instanceBeans();
&&&&&&& this.injectObject();
&&&& *为bean对象的属性注入值
&&& privatevoid injectObject() {
&&&&&&& for(BeanDefinition beanDefinition : beanDefines){
&&&&&&&&&&& Object bean = sigletons.get(beanDefinition.getId());
&&&&&&&&&&& if(bean!=null){
&&&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&&&& PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
&&&&&&&&&&&&&&&&&&& for(PropertyDefinition propertyDefinition : beanDefinition.getPropertys()){
&&&&&&&&&&&&&&&&&&&&&&& for(PropertyDescriptor properdesc : ps){
&&&&&&&&&&&&&&&&&&&&&&&&&&& if(propertyDefinition.getName().equals(properdesc.getName())){
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Method setter = properdesc.getWriteMethod();//获取属性的setter方法 ,private
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(setter!=null){
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Object value = sigletons.get(propertyDefinition.getRef());
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& setter.setAccessible(true);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& setter.invoke(bean, value);//把引用对象注入到属性
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& } catch (Exception e) {
&&&&&&&&&&&&&&& }
&&&&&&&&&&& }
&&&& *完成bean的实例化
&&& privatevoid instanceBeans() {
&&&&&&& for(BeanDefinition beanDefinition : beanDefines){
&&&&&&&&&&& try {
&&&&&&&&&&&&&&& if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))
&&&&&&&&&&&&&&&&&&& sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
&&&&&&&&&&& } catch (Exception e) {
&&&&&&&&&&&&&&& e.printStackTrace();
&&&&&&&&&&& }
&&&& *读取xml配置文件
&&&& *@paramfilename
&&& privatevoid readXML(String filename) {
&&&&&&&&&& SAXReader saxReader = new SAXReader();&&
&&&&&&&&&&& Document document=&&
&&&&&&&&&&& try{
&&&&&&&&&&&& URL xmlpath = this.getClass().getClassLoader().getResource(filename);
&&&&&&&&&&&& document = saxReader.read(xmlpath);
&&&&&&&&&&&& Map&String,String& nsMap = new HashMap&String,String&();
&&&&&&&&&&&& nsMap.put("ns","http://www.springframework.org/schema/beans");//加入命名空间
&&&&&&&&&&&& XPath xsub = document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径
&&&&&&&&&&&& xsub.setNamespaceURIs(nsMap);//设置命名空间
&&&&&&&&&&&& List&Element& beans = xsub.selectNodes(document);//获取文档下所有bean节点
&&&&&&&&&&&& for(Element element: beans){
&&&&&&&&&&&&&&& String id = element.attributeValue("id");//获取id属性值
&&&&&&&&&&&&&&& String clazz = element.attributeValue("class"); //获取class属性值&&&&&&&
&&&&&&&&&&&&&&& BeanDefinition beanDefine = new BeanDefinition(id, clazz);
&&&&&&&&&&&&&&& XPath propertysub = element.createXPath("ns:property");
&&&&&&&&&&&&&&& propertysub.setNamespaceURIs(nsMap);//设置命名空间
&&&&&&&&&&&&&&& List&Element& propertys = propertysub.selectNodes(element);
&&&&&&&&&&&&&&& for(Element property : propertys){&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&& String propertyName = property.attributeValue("name");
&&&&&&&&&&&&&&&& String propertyref = property.attributeValue("ref");
&&&&&&&&&&&&&&&& PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyref);
&&&&&&&&&&&&&&&& beanDefine.getPropertys().add(propertyDefinition);
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& beanDefines.add(beanDefine);
&&&&&&&&&&&& }
&&&&&&&&&&& }catch(Exception e){&&
&&&&&&&&&&&&&&& e.printStackTrace();
&&&&&&&&&&& }
&&&& *获取bean实例
&&&& *@parambeanName
&&&& *@return
&&& public Object getBean(String beanName){
&&&&&&& returnthis.sigletons.get(beanName);
十二、Spring 开发的好处
a)&&&&&& 降低组件之间的耦合度,实现软件各层之间的解耦
Controller -- Service -- Dao
b) 可是使用容器提供的众多服务
可使用容器提供的众多服务:事务管理服务(事务传播,无需手工控制事务)、JMS服务、Spring core核心服务、持久化服务、其他……
c) 容器提供单例模式支持,开发人员不再需要自己编写实现代码
d) 容器提供了AOP技术,利用它狠容易实现如权限拦截,运行期监控等功能
e) 容器提供了众多的辅助类,使用这些类,能够加快应用的开发,如:Jdbc Template、Hibernate Template
f) Spring 对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts等,这样更便于应用的开发
十三、 Spring DI配置文件减肥(Spring2.0 –Spring2.5的升级)
1.@Resource注解
2.注解使Spring 自动扫描和管理bean
扫描路径:&context:component-scan base-package=”cn.itcast” /&,将会扫描该包下包括其子包的类
@Component:泛指组件、当组件不好归类的时候,我们可以使用这个注解进行标注
@Service:用于标注业务层组件
@Controller:用于标注控制层组件(如struts中的action)
@Repository:用于标注数据访问组件,即DAO组件
此时bean默认的名称为类全名首写字母小写,也可指定bean名称,如
@Service(“personService”)
下面有几个例子:
service组件的注解
package cn.itcast.service.
import javax.annotation.PostC
import javax.annotation.PreD
import org.springframework.stereotype.S
import cn.itcast.dao.PersonD
import cn.itcast.service.PersonS
@Service("personService") @Scope("prototype")&&& //这样可以修改bean作用域
public class PersonServiceBean implements PersonService {
&&& //@Autowired(required=false) @Qualifier("personDaoxxxx")
&&& private PersonDao personD
&&& //初始化bean时会执行该方法的注解(ejb3中同样应用)
&&& @PostConstruct
&&& public void init(){
&&&&&&& System.out.println("初始化");
&&& //销毁bean之前会执行该方法的注解(ejb3中同样应用)
&&& @PreDestroy
&&& public void destory(){
&&&&&&& System.out.println("开闭资源");
&&& public void setPersonDao(PersonDao personDao) {
&&&&&&& this.personDao = personD
&&& public void save(){
&&&&&&& personDao.add();
dao组件的注解
package cn.itcast.dao.
import org.springframework.stereotype.R
import cn.itcast.dao.PersonD
@Repository
public class PersonDaoBean implements PersonDao {
&&& public void add(){
&&&&&&& System.out.println("执行PersonDaoBean中的add()方法");
小结:@PostConstruct 和 @PreDestroy的补充
Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,您既可以通过实现 InitializingBean/DisposableBean 接口来定制初始化之后 / 销毁之前的操作方法,也可以通过 &bean& 元素的 init-method/destroy-method 属性指定初始化之后 / 销毁之前调用的操作方法
使用时只需要在方法前标注 @PostConstruct 或 @PreDestroy,这些方法就会在 Bean 初始化后或销毁之前被 Spring容器执行了,我们知道,不管是通过实现 InitializingBean/DisposableBean 接口,还是通过 &bean& 元素的 init-method/destroy-method 属性进行配置,都只能为 Bean 指定一个初始化 / 销毁的方法。但是使用 @PostConstruct 和 @PreDestroy 注释却可以指定多个初始化 / 销毁方法,那些被标注 @PostConstruct 或 @PreDestroy 注释的方法都会在初始化 / 销毁时被执行。
浏览: 166678 次
来自: 印度
可以看看这篇文章,这个是struts教程网上一个简单的例子,构 ...
菜鸟不再菜 写道楼主很明显没有说明守护线程到底是怎么服务Use ...
要搞个executor和nio的结合,差不多
纠正楼主一个问题‘如果四个队员都在忙时,再有新的任务,这个小组 ...
josico 写道楼主写的第一个例子貌似死锁了
程序一致跑不 ...

我要回帖

更多关于 spring ioc容器 的文章

 

随机推荐