- 浏览: 253422 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
pshaoyi:
连接创建没问题,在执行的时候就报错了。Caused by: c ...
jdbc连接池简单封装 -
imbangbang:
中文乱码,没有解决掉
Java实现Zip压缩与解压(解决中文乱码问题) -
chjy1983:
麻烦也发份给我,chl_82@126.com,谢谢!
Java实现Zip压缩与解压(解决中文乱码问题) -
jidacwj:
楼主写的这个有问题呀首先,多线程分割文件第45行,我尝试打印每 ...
Java 大文件读取排序 -
www6wzk:
非常好的学习例子,十分感谢!
Jbpm工作流实例—报销申请
学习Spring IOC之前我们先看看下面的例子:
首先我们有这样一个需求.
使用U盘来存储资料,这个需求很简单
我们可以使用下面代码实现:
但是很快我们发现一个问题,SaveUtil这个类严重依赖usb这个对象
如果我们现在需要使用移动硬盘来存储资料,程序无法重用,
我们引入公用接口Isave并且对上面类做修改
然后我们的存储类都继承这个接口
这样修改之后我们只需要在实例化SaveUtil的时候传入相应的存储类就可以实现需求上的变化
很好的降低了程序之间的依赖关系,这种就是简单的控制反转.
所谓控制反转就是应用本身不负责依赖对象的创建和维护,而是交由外部容器负责.这样控制权就转移到了外部容器
控制权的转移就是所谓的控制反转.
Spring是一个开源的IOC(控制反转)和AOP(面向切面)的容器框架,使用Spring可以简化我们的开发.
开发中需要的jar包有spring.jar 和 common-logging.jar
第一个Spring应用程序,仍然使用上面的存储资料的例子
导入spring.jar和common-logging.jar到工程中
在类路径下建立一个bean.xml文件,这个文件就是spring的配置文件,通过这个配置文件我们可以使用spring对bean进行管理
首先我们配置好我们的bean对象
Spring提供了访问bean对象的一系列类,继承自ApplicationContext这个接口
程序中我们使用ClassPathXmlApplicationContext来访问我们的bean对象
运行程序后发现输出结果为:
using usb to save!!!
using mobile disk to save!!!
这里有这样一个疑问:我们的类是什么时候实例化的呢.
原来在运行了下面这句代码之后
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
Spring容器就会根据bean.xml的配置信息,通过发射机制实例化我们的bean.
我们可以写一个程序来模拟Spring容器的操作:BeanDefinition.java是bean的定义类BeanContainer.java为容器类
(默认情况下,如果配置了bean的属性如:lazy-init="true"等,则spring容器会在第一次调用getBean方法时实例化bean,
如果希望所有bean都延迟加载 则可以在beans标签上设置default-lazy-init="true")
Spring默认实例化出来的对象都是单例singleton的.
可以做如下测试:
通过比较两次拿到的对象,比较他们的引用,发现返回true,说明两次获取到的是同一个对象
当然我们可以设置bean的scope属性使我们每次都得到新的对象.scope有两种值可选singleton和prototype
spring中默认为bean设置了singleton,所以每次拿到的都是同一个对象
修改我们的bean.xml
再次运行上面的Test类发现输出结果为false 说明我们的配置生效了. 具体使用哪种bean的生成方式根据实际情况而定,一般采取默认的singleton方式
spring实例化bean有三种方式
第一种使用类构造器:
<bean id="usb" class="com.royzhou.start.Usb"></bean>
第二种使用静态工厂方法:
<bean id="usb" class="com.royzhou.start.Usb" factory-method="createUsb"></bean>
第三种使用实例工厂方法:
<bean id="usbFactory" class="com.royzhou.start.UsbFactory"></bean>
<bean id="usb" factory-bean="usbFactory" factory-method="createUsb"></bean>
指定bean的初始化方法和销毁方法
可以通过指定bean标签的init-method和destroy-method来指定bean的初始化方法和销毁方法
<bean id="usb" class="com.royzhou.start.Usb" init-method="init" destroy-method="destroy"></bean>
bean的销毁我们可以通过AbstractApplicationContext提供的close()方法来关闭spring容器实现
控制台输出结果:
I am constructor
I am initialized!!!!
I am destoryed!!!!
可以看出:使用类构造器最先执行实例化 然后执行init-method 最后执行destroy-method
注入依赖对象:
所谓依赖注入就是指在运行期间,由外部容器动态的将依赖对象注入到组件当中.
通过Spring把对象注入到我们的组件内部从而实现控制反转.
依然使用上面的存储资料的例子,修改SaveUtil类为save属性增加Setter方法:
然后修改我们的bean.xml文件如下:
其中SaveUtil在配置的时候我们为其属性save设置了一个ref值,指向MobileDisk
这里实际上就是我们通过spring容器将MobileDisk对象注入到SaveUtil这个类中
编写我们的测试类:
输出结果为:
using mobile disk to save!!!
说明我们的MobileDisk对象成功注入到SaveUtil中
修改一下ref值为usb
重新运行测试类
输出结果为:
using usb to save!!!
可以看出,使用spring的依赖注入可以极大的降低程序之间的耦合,而一切只需要通过简单修改配置文件就可以实现
重新修改我们的BeanContainer.java类使其支持注入对象:
为此我们需要增加一个PropertyDefinition.java类,用来存放property属性:
重新修改之后的BeanContainer.java类
继续运行我们的测试类Test.java
发现输出结果与之前使用Spring容器时一致......
Spring的依赖注入包括基本对象的注入以及其他bean的注入
基本对象的注入使用如下:
在bean.xml中我们可以注入id和name
<bean id="simpleBean" class="com.royzhou.start.SimpleInjectBean">
<property name="id" value="000001"></property> //通过setter注入
<constructor-arg index="0" value="royzhou"></constructor-arg> //通过构造函数注入
</bean>
bean的注入有两种情况:
1:
<bean id="SaveUtil" class="com.royzhou.start.SaveUtil">
<property name="save" ref="MobileDisk"></property>
</bean>
通过property的ref属性注入其他bean
2:
使用内部bean,注意该Bean只能在这个bean中使用,不能被其他bean占用
<bean id="SaveUtil" class="com.royzhou.start.SaveUtil">
<property name="save">
<bean class="com.royzhou.start.MobileDisk" />
</property>
</bean>
继续完善我们的BeanContainer类使其支持基本属性的注入:
<bean id="simpleBean" class="com.royzhou.start.SimpleInjectBean">
<property name="id" value="000001"></property>
<property name="name" value="royzhou"></property>
</bean>
修改PropertyDefinition.java加入value属性
修改BeanContainer类:
测试类如下:
运行Test.java类
后台输出:
000001:royzhou
说明我们的BeanContainer很好的支持了基本对象的注入.
集合类型的注入(List/Set/Map/Properties)
集合注入类CollectionInject.java,包含List/Set/Map/Properties四种类型
在bean.xml中配置注入值:
编写我们的测试类:
运行之后输出预期结果:
================list===============
list1
list2
list3
================set===============
set1
set2
set3
================map===============
map1:=mapValue1
map2:=mapValue2
map3:=mapValue3
================properties===============
prop3:=propValue3
prop2:=propValue2
prop1:=propValue1
Spring的依赖注入可以使用手工装配和自动装配,建议使用手工装配,因为自动装配有时变得难以控制,可能导致无法预见的问题
手工注入有三种方式:
1-使用构造器注入
主要是在bean中配置<constructor-arg></constructor-arg>,需要设置其inedx(参数位置,从0开始),value或者ref属性的值
如:(
<constructor-arg index="0" value="royzhou"></constructor-arg>
<constructor-arg index="1" ref="otherBean"></constructor-arg>
)
2-使用setter注入(也就是我们上面程序所使用的注入方式)
3-使用Field注入(用于注解方式Annotation)
为了简化XML文件的配置,Spring2.5增加了注解功能来实现依赖对象的注入
使用注解方式我们必须修改我们的bean.xml文件如下:
上述配置主要是帮我们注册了多个对注解进行解析处理的解析器.才能使我们的注解生效
可采用两种注解方式将对象注入到组件中
@AutoWire(Spring提供): 默认按类型在Spring容器中寻找类型匹配的Bean
@Resource(JDK提供): 默认按照名称在Spring容器中寻找类型匹配的Bean,如果找不到则采用类型寻找
同时我们可以为注解指定名称即使用(@Resource(name="***"))指定寻找的名称
如果没有指定name属性 则根据注解的属性的名称将第一个字母改成小写,以此为name的值去寻找
建议采用@Resource方式进行注解,必须导入common-annotations.jar包
下面我们使用注解方式来注入对象
bean.xml简化为如下:
修改之前的SaveUtil类
编写测试类:
运行结果:
using usb to save!!!
说明我们的注解生效了...
去掉name属性再次运行发现抛出异常信息:
No unique bean of type [com.royzhou.start.ISave] is defined: expected single matching bean but found 2: [usb, MobileDisk]
由此可见在没有设置name属性的时候spring会去寻找实现ISave接口的类:Usb和MobileDisk,因为找到的类型并不是唯一的,所以抛出上面异常信息.
我们也可以给一个属性的setter方法上加上注解:
修改SaveUtil.java
运行之后反正结果正常,说明注解也生效了...
现在我们继续完善之前的BeanContainer类,使其支持注解方式将对象注入到组件中.
首先我们需要一个注解类BeanResource
修改我们的BeanContainer.java加入注解解析器
修改SaveUtil类改用我们的注解BeanResource
重新运行测试类:
控制台输出结果为:
using mobile disk to save!!!
说明我们的容器已经正确的处理了我们自定义的注解,正常工作了....
尽管我们使用了注解方式来减少bean.xml的配置
但是如果项目中存在大量的bean对象 我们仍然需要在bean.xml中配置大量的bean
为此Spring为我们提供了一种通过在Classpath自动扫描的方式把组件纳入Spring管理
为了实现这样的功能,我们需要修改配置文件bean.xml
其中<context:component-scan base-package="com.royzhou.start" /> 告诉spring容器我们要扫描com.royzhou.start包(包括子包)下的类,结合类上定义的注解
来确定是不是要将这些bean纳入spring管理
采用这种方式我们需要给那些要交给spring管理的类加上注解:
@Service : 用于标注业务层
@Controller : 用于标注控制层
@Repository : 用于标注DAO层
当组件不好归类时,我们可以使用@Component注解
使用之前存储例子测试:
运行测试程序输出:
using mobile disk to save!!!
说明我们的注解已经生效,使用这种方式可以很大程度的减少了bean.xml中配置大量bean的复杂工作,加速我们的开发速度.
这里可能会有一些疑问:我们之前在bean.xml中配置的scope,init-method,destroy-method之类的方法现在如何配置.
Spring同样为我们提供了,也可以使用注解来实现:
如:
使用@Scope("prototype")可以设置bean的作用域
使用@PostConstruct 可以设置bean的初始化方法
使用@PreDestroy 可以设置bean的销毁方法
从上面的例子中我们可以得出结论:
使用Spring的IOC(控制反转)为我们的开发带来了很大的便利,很大程度的降低了程序之间的耦合,增强了系统的可维护性.
首先我们有这样一个需求.
使用U盘来存储资料,这个需求很简单
我们可以使用下面代码实现:
public class SaveUtil { private Usb usb = new Usb(); public void save() { usb.save(); } }
public class Usb { public void save() { System.out.println("using use to save!!"); } }
但是很快我们发现一个问题,SaveUtil这个类严重依赖usb这个对象
如果我们现在需要使用移动硬盘来存储资料,程序无法重用,
我们引入公用接口Isave并且对上面类做修改
public interface ISave { public void save(); }
然后我们的存储类都继承这个接口
public class Usb implements ISave { public void save() { System.out.println("using use to save!!"); } }
public class MobileDisk implements ISave { public void save() { System.out.println("using mobiledisk to save!!"); } }
public class SaveUtil { private Isave iSave; public SaveUtil(Isave iSave) { this.iSave = iSave; } public void save() { iSave.save(); } }
这样修改之后我们只需要在实例化SaveUtil的时候传入相应的存储类就可以实现需求上的变化
很好的降低了程序之间的依赖关系,这种就是简单的控制反转.
所谓控制反转就是应用本身不负责依赖对象的创建和维护,而是交由外部容器负责.这样控制权就转移到了外部容器
控制权的转移就是所谓的控制反转.
Spring是一个开源的IOC(控制反转)和AOP(面向切面)的容器框架,使用Spring可以简化我们的开发.
开发中需要的jar包有spring.jar 和 common-logging.jar
第一个Spring应用程序,仍然使用上面的存储资料的例子
导入spring.jar和common-logging.jar到工程中
在类路径下建立一个bean.xml文件,这个文件就是spring的配置文件,通过这个配置文件我们可以使用spring对bean进行管理
<?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-2.5.xsd"> </beans>
首先我们配置好我们的bean对象
<?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-2.5.xsd"> <bean id="usb" class="com.royzhou.start.Usb"></bean> <bean id="MobileDisk" class="com.royzhou.start.MobileDisk"></bean> </beans>
Spring提供了访问bean对象的一系列类,继承自ApplicationContext这个接口
程序中我们使用ClassPathXmlApplicationContext来访问我们的bean对象
public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); Usb usb = (Usb)ctx.getBean("usb"); usb.save(); MobileDisk md = (MobileDisk)ctx.getBean("MobileDisk"); md.save(); } }
运行程序后发现输出结果为:
using usb to save!!!
using mobile disk to save!!!
这里有这样一个疑问:我们的类是什么时候实例化的呢.
原来在运行了下面这句代码之后
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
Spring容器就会根据bean.xml的配置信息,通过发射机制实例化我们的bean.
我们可以写一个程序来模拟Spring容器的操作:BeanDefinition.java是bean的定义类BeanContainer.java为容器类
package com.royzhou.start; import java.util.ArrayList; import java.util.List; public class BeanDefinition { private String id; private String className; private List<PropertyDefinition> propertys = new ArrayList<PropertyDefinition>(); public BeanDefinition(String id, String className) { this.id = id; this.className = className; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public List<PropertyDefinition> getPropertys() { return propertys; } public void setPropertys(List<PropertyDefinition> propertys) { this.propertys = propertys; } }
package com.royzhou.start; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.SAXReader; public class BeanContainer { private List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); private Map<String, Object> singletons = new HashMap<String, Object>(); public BeanContainer(String fileName) { readXML(fileName); instanceBeans(); } /** * 实例化bean对象并储存在Map中 * */ public void instanceBeans() { String id = null; String className = null; Object objectBean = null; for (BeanDefinition bd : beanDefinitions) { id = bd.getId(); className = bd.getClassName(); if (className != null && !"".equals(className.trim())) { try { objectBean = Class.forName(className).newInstance(); singletons.put(id, objectBean); } catch(Exception e) { System.out.println("实例化bean:" + className + "出错!!!"); e.printStackTrace(); } } } } /** * 读取配置文件 * @param fileName */ @SuppressWarnings("unchecked") public void readXML(String fileName) { URL url = null; SAXReader reader = null; Document doc; try { url = this.getClass().getClassLoader().getResource(fileName); reader = new SAXReader(); doc = reader.read(url); Map<String, String> nsMap = new HashMap<String, String>(); nsMap.put("ns", "http://www.springframework.org/schema/beans"); XPath xPath = doc.createXPath("//ns:beans/ns:bean"); //创建查询路径//ns:beans/ns:bean xPath.setNamespaceURIs(nsMap); //设置命名空间 List<Element> elements = xPath.selectNodes(doc); //查询doc的beans下的所有bean元素 for (Element e : elements) { String id = e.attributeValue("id"); String className = e.attributeValue("class"); BeanDefinition bd = new BeanDefinition(id, className); beanDefinitions.add(bd); } } catch (DocumentException e1) { System.out.println("解析配置文件" + fileName + "出错!!!"); e1.printStackTrace(); } } /** * 获取bean实例,单例 * @param id * @return */ public Object getBean(String id) { return singletons.get(id); } }
(默认情况下,如果配置了bean的属性如:lazy-init="true"等,则spring容器会在第一次调用getBean方法时实例化bean,
如果希望所有bean都延迟加载 则可以在beans标签上设置default-lazy-init="true")
Spring默认实例化出来的对象都是单例singleton的.
可以做如下测试:
public class Test { public static void main(String[] args) { BeanContainer ctx = new BeanContainer("bean.xml"); Usb usb = (Usb)ctx.getBean("usb"); Usb usb1 = (Usb)ctx.getBean("usb"); System.out.println(usb == usb1); } }
通过比较两次拿到的对象,比较他们的引用,发现返回true,说明两次获取到的是同一个对象
当然我们可以设置bean的scope属性使我们每次都得到新的对象.scope有两种值可选singleton和prototype
spring中默认为bean设置了singleton,所以每次拿到的都是同一个对象
修改我们的bean.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-2.5.xsd"> <bean id="usb" class="com.royzhou.start.Usb" scope="prototype"></bean> <bean id="MobileDisk" class="com.royzhou.start.MobileDisk"></bean> </beans>
再次运行上面的Test类发现输出结果为false 说明我们的配置生效了. 具体使用哪种bean的生成方式根据实际情况而定,一般采取默认的singleton方式
spring实例化bean有三种方式
第一种使用类构造器:
<bean id="usb" class="com.royzhou.start.Usb"></bean>
第二种使用静态工厂方法:
<bean id="usb" class="com.royzhou.start.Usb" factory-method="createUsb"></bean>
public class Usb implements ISave { public void save() { System.out.println("using usb to save!!!"); } public static Usb createUsb() { return new Usb(); } }
第三种使用实例工厂方法:
<bean id="usbFactory" class="com.royzhou.start.UsbFactory"></bean>
<bean id="usb" factory-bean="usbFactory" factory-method="createUsb"></bean>
public class UsbFactory { public Usb createUsb() { return new Usb(); } }
指定bean的初始化方法和销毁方法
可以通过指定bean标签的init-method和destroy-method来指定bean的初始化方法和销毁方法
<bean id="usb" class="com.royzhou.start.Usb" init-method="init" destroy-method="destroy"></bean>
bean的销毁我们可以通过AbstractApplicationContext提供的close()方法来关闭spring容器实现
package com.royzhou.start; public class Usb implements ISave { public void init() { System.out.println("I am initialized!!!!"); } public Usb() { System.out.println("I am constructor"); } public void save() { System.out.println("using usb to save!!!"); } public void destroy() { System.out.println("I am destoryed!!!!"); } }
package com.royzhou.test; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.royzhou.start.Usb; public class Test { public static void main(String[] args) { AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); Usb usb = (Usb)ctx.getBean("usb"); ctx.close(); } }
控制台输出结果:
I am constructor
I am initialized!!!!
I am destoryed!!!!
可以看出:使用类构造器最先执行实例化 然后执行init-method 最后执行destroy-method
注入依赖对象:
所谓依赖注入就是指在运行期间,由外部容器动态的将依赖对象注入到组件当中.
通过Spring把对象注入到我们的组件内部从而实现控制反转.
依然使用上面的存储资料的例子,修改SaveUtil类为save属性增加Setter方法:
public class Usb implements ISave { public void save() { System.out.println("using use to save!!"); } }
public class MobileDisk implements ISave { public void save() { System.out.println("using mobiledisk to save!!"); } }
public class SaveUtil { private Isave iSave; public SaveUtil(Isave iSave) { this.iSave = iSave; } public void setSave(ISave save) { this.save = save; } public void save() { iSave.save(); } }
然后修改我们的bean.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-2.5.xsd"> <bean id="usb" class="com.royzhou.start.Usb"></bean> <bean id="MobileDisk" class="com.royzhou.start.MobileDisk"></bean> <bean id="SaveUtil" class="com.royzhou.start.SaveUtil"> <property name="save" ref="MobileDisk"></property> </bean> </beans>
其中SaveUtil在配置的时候我们为其属性save设置了一个ref值,指向MobileDisk
这里实际上就是我们通过spring容器将MobileDisk对象注入到SaveUtil这个类中
编写我们的测试类:
package com.royzhou.test; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.royzhou.start.SaveUtil; public class Test { public static void main(String[] args) { AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); SaveUtil su = (SaveUtil)ctx.getBean("SaveUtil"); su.save(); } }
输出结果为:
using mobile disk to save!!!
说明我们的MobileDisk对象成功注入到SaveUtil中
修改一下ref值为usb
重新运行测试类
输出结果为:
using usb to save!!!
可以看出,使用spring的依赖注入可以极大的降低程序之间的耦合,而一切只需要通过简单修改配置文件就可以实现
重新修改我们的BeanContainer.java类使其支持注入对象:
为此我们需要增加一个PropertyDefinition.java类,用来存放property属性:
package com.royzhou.start; public class PropertyDefinition { private String name; private String ref; public PropertyDefinition(String name, String ref) { super(); this.name = name; this.ref = ref; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } }
重新修改之后的BeanContainer.java类
package com.royzhou.start; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.SAXReader; public class BeanContainer { private List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); private Map<String, Object> singletons = new HashMap<String, Object>(); public BeanContainer(String fileName) { readXML(fileName); instanceBeans(); injectBeans(); } /** * 实例化bean对象并储存在Map中 * */ public void instanceBeans() { String id = null; String className = null; Object objectBean = null; for (BeanDefinition bd : beanDefinitions) { id = bd.getId(); className = bd.getClassName(); if (className != null && !"".equals(className.trim())) { try { objectBean = Class.forName(className).newInstance(); singletons.put(id, objectBean); } catch(Exception e) { System.out.println("实例化bean:" + className + "出错!!!"); e.printStackTrace(); } } } } /** * 注入依赖对象 * */ public void injectBeans() { Object objectBean = null; Object refBean = null; BeanInfo beanInfo = null; PropertyDescriptor[] propertyDescriptors = null; Method setter = null; for (BeanDefinition bd : beanDefinitions) { objectBean = singletons.get(bd.getId()); if(objectBean!=null) { List<PropertyDefinition> propertys = bd.getPropertys(); if(propertys!=null && propertys.size()>0) { try { beanInfo = Introspector.getBeanInfo(objectBean.getClass()); propertyDescriptors = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : propertyDescriptors) { for(PropertyDefinition propertyDefinition : propertys) { if(propertyDefinition.getName().equals(propertyDescriptor.getName())) { setter = propertyDescriptor.getWriteMethod(); //获取setter方法 if(setter!=null) { refBean = singletons.get(propertyDefinition.getRef()); setter.setAccessible(true); //避免setter方法是private的时候抛出不可访问的异常 setter.invoke(objectBean,new Object[]{refBean}); //通过setter方法将对象注入到组件中 } break; } } } } catch (Exception e) { System.out.println(bd.getClassName() + "注入bean对象出错!!!"); e.printStackTrace(); } } } } } /** * 读取配置文件 * @param fileName */ @SuppressWarnings("unchecked") public void readXML(String fileName) { URL url = null; SAXReader reader = null; Document doc; try { url = this.getClass().getClassLoader().getResource(fileName); reader = new SAXReader(); doc = reader.read(url); Map<String, String> nsMap = new HashMap<String, String>(); nsMap.put("ns", "http://www.springframework.org/schema/beans"); XPath xPath = doc.createXPath("//ns:beans/ns:bean"); //创建查询路径//ns:beans/ns:bean xPath.setNamespaceURIs(nsMap); //设置命名空间 List<Element> elements = xPath.selectNodes(doc); //查询doc的beans下的所有bean元素 for (Element e : elements) { String id = e.attributeValue("id"); String className = e.attributeValue("class"); BeanDefinition bd = new BeanDefinition(id, className); XPath propertyPath = e.createXPath("ns:property"); propertyPath.setNamespaceURIs(nsMap); List<Element> propertys = propertyPath.selectNodes(e); for (Element property : propertys) { String name = property.attributeValue("name"); String ref = property.attributeValue("ref"); PropertyDefinition pd = new PropertyDefinition(name, ref); bd.getPropertys().add(pd); } beanDefinitions.add(bd); } } catch (DocumentException e1) { System.out.println("解析配置文件" + fileName + "出错!!!"); e1.printStackTrace(); } } /** * 获取bean实例,单例 * @param id * @return */ public Object getBean(String id) { return singletons.get(id); } }
继续运行我们的测试类Test.java
package com.royzhou.test; import com.royzhou.start.BeanContainer; import com.royzhou.start.SaveUtil; public class Test { public static void main(String[] args) { BeanContainer ctx = new BeanContainer("bean.xml"); SaveUtil su = (SaveUtil)ctx.getBean("SaveUtil"); su.save(); } }
发现输出结果与之前使用Spring容器时一致......
Spring的依赖注入包括基本对象的注入以及其他bean的注入
基本对象的注入使用如下:
package com.royzhou.start; public class SimpleInjectBean { private String id; private String name; public SimpleInjectBean(String name) { this.name = 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; } public String toString() { return this.id + ":" + this.name; } }
在bean.xml中我们可以注入id和name
<bean id="simpleBean" class="com.royzhou.start.SimpleInjectBean">
<property name="id" value="000001"></property> //通过setter注入
<constructor-arg index="0" value="royzhou"></constructor-arg> //通过构造函数注入
</bean>
bean的注入有两种情况:
1:
<bean id="SaveUtil" class="com.royzhou.start.SaveUtil">
<property name="save" ref="MobileDisk"></property>
</bean>
通过property的ref属性注入其他bean
2:
使用内部bean,注意该Bean只能在这个bean中使用,不能被其他bean占用
<bean id="SaveUtil" class="com.royzhou.start.SaveUtil">
<property name="save">
<bean class="com.royzhou.start.MobileDisk" />
</property>
</bean>
继续完善我们的BeanContainer类使其支持基本属性的注入:
<bean id="simpleBean" class="com.royzhou.start.SimpleInjectBean">
<property name="id" value="000001"></property>
<property name="name" value="royzhou"></property>
</bean>
修改PropertyDefinition.java加入value属性
package com.royzhou.start; public class PropertyDefinition { private String name; private String value; private String ref; public PropertyDefinition(String name, String value, String ref) { super(); this.name = name; this.value = value; this.ref = ref; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
修改BeanContainer类:
package com.royzhou.start; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.ConvertUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.SAXReader; public class BeanContainer { private List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); private Map<String, Object> singletons = new HashMap<String, Object>(); public BeanContainer(String fileName) { readXML(fileName); instanceBeans(); injectBeans(); } /** * 实例化bean对象并储存在Map中 * */ public void instanceBeans() { String id = null; String className = null; Object objectBean = null; for (BeanDefinition bd : beanDefinitions) { id = bd.getId(); className = bd.getClassName(); if (className != null && !"".equals(className.trim())) { try { objectBean = Class.forName(className).newInstance(); singletons.put(id, objectBean); } catch(Exception e) { System.out.println("实例化bean:" + className + "出错!!!"); e.printStackTrace(); } } } } /** * 注入依赖对象 * */ public void injectBeans() { Object objectBean = null; Object refBean = null; BeanInfo beanInfo = null; PropertyDescriptor[] propertyDescriptors = null; Method setter = null; String ref = null; Object value = null; for (BeanDefinition bd : beanDefinitions) { objectBean = singletons.get(bd.getId()); if(objectBean!=null) { List<PropertyDefinition> propertys = bd.getPropertys(); if(propertys!=null && propertys.size()>0) { try { beanInfo = Introspector.getBeanInfo(objectBean.getClass()); propertyDescriptors = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : propertyDescriptors) { for(PropertyDefinition propertyDefinition : propertys) { if(propertyDefinition.getName().equals(propertyDescriptor.getName())) { setter = propertyDescriptor.getWriteMethod(); //获取setter方法 if(setter!=null) { ref = propertyDefinition.getRef(); if(ref!=null && !"".equals(ref)) { refBean = singletons.get(ref); setter.setAccessible(true); //避免setter方法是private的时候抛出不可访问的异常 setter.invoke(objectBean,new Object[]{refBean}); //通过setter方法将对象注入到组件中 } else { //使用common-beanutils包中的ConvertUtils将值转换成对应的类型 value = ConvertUtils.convert(propertyDefinition.getValue(), propertyDescriptor.getPropertyType()); setter.setAccessible(true); //避免setter方法是private的时候抛出不可访问的异常 setter.invoke(objectBean,new Object[]{value}); //通过setter方法将对象注入到组件中 } } break; } } } } catch (Exception e) { System.out.println(bd.getClassName() + "注入bean对象出错!!!"); e.printStackTrace(); } } } } } /** * 读取配置文件 * @param fileName */ @SuppressWarnings("unchecked") public void readXML(String fileName) { URL url = null; SAXReader reader = null; Document doc; try { url = this.getClass().getClassLoader().getResource(fileName); reader = new SAXReader(); doc = reader.read(url); Map<String, String> nsMap = new HashMap<String, String>(); nsMap.put("ns", "http://www.springframework.org/schema/beans"); XPath xPath = doc.createXPath("//ns:beans/ns:bean"); //创建查询路径//ns:beans/ns:bean xPath.setNamespaceURIs(nsMap); //设置命名空间 List<Element> elements = xPath.selectNodes(doc); //查询doc的beans下的所有bean元素 for (Element e : elements) { String id = e.attributeValue("id"); String className = e.attributeValue("class"); BeanDefinition bd = new BeanDefinition(id, className); XPath propertyPath = e.createXPath("ns:property"); propertyPath.setNamespaceURIs(nsMap); List<Element> propertys = propertyPath.selectNodes(e); for (Element property : propertys) { String name = property.attributeValue("name"); String value = property.attributeValue("value"); String ref = property.attributeValue("ref"); PropertyDefinition pd = new PropertyDefinition(name,value, ref); bd.getPropertys().add(pd); } beanDefinitions.add(bd); } } catch (DocumentException e1) { System.out.println("解析配置文件" + fileName + "出错!!!"); e1.printStackTrace(); } } /** * 获取bean实例,单例 * @param id * @return */ public Object getBean(String id) { return singletons.get(id); } }
测试类如下:
package com.royzhou.start; public class SimpleInjectBean { private String id; private String name; public SimpleInjectBean() { //由于BeanContainer在实例化时调用的是无参构造函数,故加入此方法避免异常 } public SimpleInjectBean(String name) { this.name = 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; } public String toString() { return this.id + ":" + this.name; } }
运行Test.java类
package com.royzhou.test; import com.royzhou.start.BeanContainer; import com.royzhou.start.SimpleInjectBean; public class Test { public static void main(String[] args) { BeanContainer ctx = new BeanContainer("bean.xml"); SimpleInjectBean sib = (SimpleInjectBean)ctx.getBean("simpleBean"); System.out.println(sib); } }
后台输出:
000001:royzhou
说明我们的BeanContainer很好的支持了基本对象的注入.
集合类型的注入(List/Set/Map/Properties)
集合注入类CollectionInject.java,包含List/Set/Map/Properties四种类型
package com.royzhou.start; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class CollectionInject { private List<String> list = new ArrayList<String>(); private Set<String> set = new HashSet<String>(); private Map<String, Object> map = new HashMap<String, Object>(); private Properties properties = new Properties(); public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } public Map<String, Object> getMap() { return map; } public void setMap(Map<String, Object> map) { this.map = map; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } public Set<String> getSet() { return set; } public void setSet(Set<String> set) { this.set = set; } }
在bean.xml中配置注入值:
<bean id="collectionInject" class="com.royzhou.start.CollectionInject"> <property name="list"> <list> <value>list1</value> <value>list2</value> <value>list3</value> </list> </property> <property name="set"> <set> <value>set1</value> <value>set2</value> <value>set2</value> <value>set3</value> </set> </property> <property name="map"> <map> <entry key="map1" value="mapValue1"></entry> <entry key="map2" value="mapValue2"></entry> <entry key="map3" value="mapValue3"></entry> </map> </property> <property name="properties"> <props> <prop key="prop1">propValue1</prop> <prop key="prop2">propValue2</prop> <prop key="prop3">propValue3</prop> </props> </property> </bean>
编写我们的测试类:
package com.royzhou.test; import java.util.Set; import java.util.Map.Entry; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.royzhou.start.CollectionInject; public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); CollectionInject ci = (CollectionInject)ctx.getBean("collectionInject"); System.out.println("================list==============="); for(String s : ci.getList()) { System.out.println(s); } System.out.println("================set==============="); for(String s : ci.getSet()) { System.out.println(s); } System.out.println("================map==============="); Set<Entry<String,Object>> maps = ci.getMap().entrySet(); for(Entry e : maps) { System.out.println(e.getKey() + ":=" + e.getValue()); } System.out.println("================properties==============="); Set<Entry<Object,Object>> props = ci.getProperties().entrySet(); for(Entry e : props) { System.out.println(e.getKey() + ":=" + e.getValue()); } } }
运行之后输出预期结果:
================list===============
list1
list2
list3
================set===============
set1
set2
set3
================map===============
map1:=mapValue1
map2:=mapValue2
map3:=mapValue3
================properties===============
prop3:=propValue3
prop2:=propValue2
prop1:=propValue1
Spring的依赖注入可以使用手工装配和自动装配,建议使用手工装配,因为自动装配有时变得难以控制,可能导致无法预见的问题
手工注入有三种方式:
1-使用构造器注入
主要是在bean中配置<constructor-arg></constructor-arg>,需要设置其inedx(参数位置,从0开始),value或者ref属性的值
如:(
<constructor-arg index="0" value="royzhou"></constructor-arg>
<constructor-arg index="1" ref="otherBean"></constructor-arg>
)
2-使用setter注入(也就是我们上面程序所使用的注入方式)
3-使用Field注入(用于注解方式Annotation)
为了简化XML文件的配置,Spring2.5增加了注解功能来实现依赖对象的注入
使用注解方式我们必须修改我们的bean.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 /> <beans>
上述配置主要是帮我们注册了多个对注解进行解析处理的解析器.才能使我们的注解生效
可采用两种注解方式将对象注入到组件中
@AutoWire(Spring提供): 默认按类型在Spring容器中寻找类型匹配的Bean
@Resource(JDK提供): 默认按照名称在Spring容器中寻找类型匹配的Bean,如果找不到则采用类型寻找
同时我们可以为注解指定名称即使用(@Resource(name="***"))指定寻找的名称
如果没有指定name属性 则根据注解的属性的名称将第一个字母改成小写,以此为name的值去寻找
建议采用@Resource方式进行注解,必须导入common-annotations.jar包
下面我们使用注解方式来注入对象
bean.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 /> <bean id="usb" class="com.royzhou.start.Usb"></bean> <bean id="MobileDisk" class="com.royzhou.start.MobileDisk"></bean> <bean id="SaveUtil" class="com.royzhou.start.SaveUtil"></bean> </beans>
修改之前的SaveUtil类
package com.royzhou.start; import javax.annotation.Resource; public class SaveUtil { @Resource(name="usb") public ISave save; public void setSave(ISave save) { this.save = save; } public void save() { save.save(); } }
编写测试类:
package com.royzhou.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.royzhou.start.SaveUtil; public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); SaveUtil su = (SaveUtil)ctx.getBean("SaveUtil"); su.save(); } }
运行结果:
using usb to save!!!
说明我们的注解生效了...
去掉name属性再次运行发现抛出异常信息:
No unique bean of type [com.royzhou.start.ISave] is defined: expected single matching bean but found 2: [usb, MobileDisk]
由此可见在没有设置name属性的时候spring会去寻找实现ISave接口的类:Usb和MobileDisk,因为找到的类型并不是唯一的,所以抛出上面异常信息.
我们也可以给一个属性的setter方法上加上注解:
修改SaveUtil.java
package com.royzhou.start; import javax.annotation.Resource; public class SaveUtil { public ISave save; @Resource(name="MobileDisk") public void setSave(ISave save) { this.save = save; } public void save() { save.save(); } }
运行之后反正结果正常,说明注解也生效了...
现在我们继续完善之前的BeanContainer类,使其支持注解方式将对象注入到组件中.
首先我们需要一个注解类BeanResource
package com.royzhou.start; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //指定运行期间检查 @Retention(RetentionPolicy.RUNTIME) //指定作用对象,可作用与Field和Method上 @Target({ElementType.FIELD,ElementType.METHOD}) public @interface BeanResource { //设置name属性,类似@Resource(name="")中的name String name() default ""; }
修改我们的BeanContainer.java加入注解解析器
package com.royzhou.start; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.ConvertUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.SAXReader; public class BeanContainer { private List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); private Map<String, Object> singletons = new HashMap<String, Object>(); public BeanContainer(String fileName) { readXML(fileName); instanceBeans(); annotationInject(); injectBeans(); } /** * 实例化bean对象并储存在Map中 * */ public void instanceBeans() { String id = null; String className = null; Object objectBean = null; for (BeanDefinition bd : beanDefinitions) { id = bd.getId(); className = bd.getClassName(); if (className != null && !"".equals(className.trim())) { try { objectBean = Class.forName(className).newInstance(); singletons.put(id, objectBean); } catch(Exception e) { System.out.println("实例化bean:" + className + "出错!!!"); e.printStackTrace(); } } } } /** * 注入依赖对象 * */ public void injectBeans() { Object objectBean = null; Object refBean = null; BeanInfo beanInfo = null; PropertyDescriptor[] propertyDescriptors = null; Method setter = null; String ref = null; Object value = null; for (BeanDefinition bd : beanDefinitions) { objectBean = singletons.get(bd.getId()); if(objectBean!=null) { List<PropertyDefinition> propertys = bd.getPropertys(); if(propertys!=null && propertys.size()>0) { try { beanInfo = Introspector.getBeanInfo(objectBean.getClass()); propertyDescriptors = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : propertyDescriptors) { for(PropertyDefinition propertyDefinition : propertys) { if(propertyDefinition.getName().equals(propertyDescriptor.getName())) { setter = propertyDescriptor.getWriteMethod(); //获取setter方法 if(setter!=null) { ref = propertyDefinition.getRef(); if(ref!=null && !"".equals(ref)) { refBean = singletons.get(ref); setter.setAccessible(true); //避免setter方法是private的时候抛出不可访问的异常 setter.invoke(objectBean,new Object[]{refBean}); //通过setter方法将对象注入到组件中 } else { //使用ConvertUtils转换成对应的类型 value = ConvertUtils.convert(propertyDefinition.getValue(), propertyDescriptor.getPropertyType()); setter.setAccessible(true); //避免setter方法是private的时候抛出不可访问的异常 setter.invoke(objectBean,new Object[]{value}); //通过setter方法将对象注入到组件中 } } break; } } } } catch (Exception e) { System.out.println(bd.getClassName() + "注入bean对象出错!!!"); e.printStackTrace(); } } } } } /** * 注解处理器 * */ public void annotationInject() { Object objectBean = null; for(String beanName : singletons.keySet()) { objectBean = singletons.get(beanName); if(objectBean!=null) { try { //解析方法中是否存在annotation PropertyDescriptor[] propertys = Introspector.getBeanInfo(objectBean.getClass()).getPropertyDescriptors(); for(PropertyDescriptor propertyDescriptor : propertys) { Method setter = propertyDescriptor.getWriteMethod(); if(setter!=null && setter.isAnnotationPresent(BeanResource.class)) { BeanResource beanResource = setter.getAnnotation(BeanResource.class); Object value = beanResource.name(); //是否设置了name属性 if(value!=null && !"".equals(value)) { value = singletons.get(value); } else { //如果没有设置name则按照属性名称查找 value = singletons.get(propertyDescriptor.getName()); //如果没有找到则按类型匹配 if(value==null) { for(String key : singletons.keySet()){ if(propertyDescriptor.getPropertyType().isAssignableFrom(singletons.get(key).getClass())){ value = singletons.get(key); break; } } } } setter.setAccessible(true); setter.invoke(objectBean, value);//把引用对象注入到属性 } } //解析字段中是否存在annotation Field[] fields = objectBean.getClass().getDeclaredFields(); for(Field field : fields) { if(field.isAnnotationPresent(BeanResource.class)) { BeanResource beanResource = field.getAnnotation(BeanResource.class); Object value = beanResource.name(); if(value!=null && !"".equals(value)) { value = singletons.get(value); } else { value = singletons.get(field.getName()); if(value==null) { for(String key : singletons.keySet()){ if(field.getType().isAssignableFrom(singletons.get(key).getClass())){ value = singletons.get(key); break; } } } } field.setAccessible(true);//允许访问private字段 field.set(objectBean, value); } } } catch (Exception e) { System.out.println("注解解析器处理出错!!!"); e.printStackTrace(); } } } } /** * 读取配置文件 * @param fileName */ @SuppressWarnings("unchecked") public void readXML(String fileName) { URL url = null; SAXReader reader = null; Document doc; try { url = this.getClass().getClassLoader().getResource(fileName); reader = new SAXReader(); doc = reader.read(url); Map<String, String> nsMap = new HashMap<String, String>(); nsMap.put("ns", "http://www.springframework.org/schema/beans"); XPath xPath = doc.createXPath("//ns:beans/ns:bean"); //创建查询路径//ns:beans/ns:bean xPath.setNamespaceURIs(nsMap); //设置命名空间 List<Element> elements = xPath.selectNodes(doc); //查询doc的beans下的所有bean元素 for (Element e : elements) { String id = e.attributeValue("id"); String className = e.attributeValue("class"); BeanDefinition bd = new BeanDefinition(id, className); XPath propertyPath = e.createXPath("ns:property"); propertyPath.setNamespaceURIs(nsMap); List<Element> propertys = propertyPath.selectNodes(e); for (Element property : propertys) { String name = property.attributeValue("name"); String value = property.attributeValue("value"); String ref = property.attributeValue("ref"); PropertyDefinition pd = new PropertyDefinition(name,value, ref); bd.getPropertys().add(pd); } beanDefinitions.add(bd); } } catch (DocumentException e1) { System.out.println("解析配置文件" + fileName + "出错!!!"); e1.printStackTrace(); } } /** * 获取bean实例,单例 * @param id * @return */ public Object getBean(String id) { return singletons.get(id); } }
修改SaveUtil类改用我们的注解BeanResource
package com.royzhou.start; public class SaveUtil { public ISave save; @BeanResource(name="MobileDisk") public void setSave(ISave save) { this.save = save; } public void save() { save.save(); } }
重新运行测试类:
package com.royzhou.test; import com.royzhou.start.BeanContainer; import com.royzhou.start.SaveUtil; public class Test { public static void main(String[] args) { BeanContainer ctx = new BeanContainer("bean.xml"); SaveUtil su = (SaveUtil)ctx.getBean("SaveUtil"); su.save(); } }
控制台输出结果为:
using mobile disk to save!!!
说明我们的容器已经正确的处理了我们自定义的注解,正常工作了....
尽管我们使用了注解方式来减少bean.xml的配置
但是如果项目中存在大量的bean对象 我们仍然需要在bean.xml中配置大量的bean
为此Spring为我们提供了一种通过在Classpath自动扫描的方式把组件纳入Spring管理
为了实现这样的功能,我们需要修改配置文件bean.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:component-scan base-package="com.royzhou.start" /> </beans>
其中<context:component-scan base-package="com.royzhou.start" /> 告诉spring容器我们要扫描com.royzhou.start包(包括子包)下的类,结合类上定义的注解
来确定是不是要将这些bean纳入spring管理
采用这种方式我们需要给那些要交给spring管理的类加上注解:
@Service : 用于标注业务层
@Controller : 用于标注控制层
@Repository : 用于标注DAO层
当组件不好归类时,我们可以使用@Component注解
使用之前存储例子测试:
package com.royzhou.start; import org.springframework.stereotype.Component; @Service public class Usb implements ISave { public void save() { System.out.println("using usb to save!!!"); } }
package com.royzhou.start; import org.springframework.stereotype.Service; @Service public class MobileDisk implements ISave { public void save() { System.out.println("using mobile disk to save!!!"); } }
package com.royzhou.start; import javax.annotation.Resource; import org.springframework.stereotype.Controller; @Controller public class SaveUtil { public ISave save; @Resource(name="mobileDisk") public void setSave(ISave save) { this.save = save; } public void save() { save.save(); } }
package com.royzhou.start; import javax.annotation.Resource; import org.springframework.stereotype.Controller; @Controller public class SaveUtil { public ISave save; //由于MobileDisk注解没有指定名称,所以默认使用类名第一个字母变小写后的字符串来查找 @Resource(name="mobileDisk") public void setSave(ISave save) { this.save = save; } public void save() { save.save(); } }
运行测试程序输出:
using mobile disk to save!!!
说明我们的注解已经生效,使用这种方式可以很大程度的减少了bean.xml中配置大量bean的复杂工作,加速我们的开发速度.
这里可能会有一些疑问:我们之前在bean.xml中配置的scope,init-method,destroy-method之类的方法现在如何配置.
Spring同样为我们提供了,也可以使用注解来实现:
如:
package com.royzhou.start; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; @Controller @Scope("prototype") public class SaveUtil { public ISave save; @PostConstruct public void init() { System.out.println("I am init method!!!"); } @Resource(name="mobileDisk") public void setSave(ISave save) { this.save = save; } public void save() { save.save(); } @PreDestroy public void destroy() { System.out.println("I am destroy method!!!"); } }
使用@Scope("prototype")可以设置bean的作用域
使用@PostConstruct 可以设置bean的初始化方法
使用@PreDestroy 可以设置bean的销毁方法
从上面的例子中我们可以得出结论:
使用Spring的IOC(控制反转)为我们的开发带来了很大的便利,很大程度的降低了程序之间的耦合,增强了系统的可维护性.
相关推荐
**Spring Ioc 实现原理详解** Spring Ioc(Inversion of Control,控制反转)是Spring框架的核心特性之一,它改变了传统应用程序中对象的创建和管理方式。在传统的软件设计中,对象的创建和依赖关系的维护通常由...
spring Ioc容器配置 IOC容器数据源配置 <!-- 配置数据源 --> destroy-method="close"> <value>org.gjt.mm.mysql.Driver <value>jdbc:mysql://localhost:3306/demo <value>root ...
Spring 框架是Java开发中的核心框架,它主要由两个关键部分组成:IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)。这两个概念是Spring框架的核心特性,极大地简化了企业...
SpringIOC是Spring Framework中的核心组件之一,负责管理应用程序中的对象、依赖关系和生命周期。 在 Spring IOC 中,对象的创建和管理是通过 BeanFactory 或 ApplicationContext 实现的。BeanFactory 是 Spring ...
标题 "Spring IOC" 描述了我们讨论的核心主题——Spring 框架中的依赖注入(Inversion of Control,简称 IOC)机制。Spring 是一个广泛应用的 Java 应用开发框架,其核心特性之一就是IOC,它极大地简化了软件组件...
Spring IoC 加载流程讲解 在本节中,我们将对 Spring IoC 加载流程进行详细的讲解,并探讨 IoC 思想和依赖倒置原则的应用。 IoC 控制反转 IoC(Inversion of Control)是指在软件设计中,将对象实例的控制权从...
Spring IOC,全称Inversion of Control,即“控制反转”,是Spring框架的核心特性之一。在传统的Java应用程序中,对象的创建和管理通常由开发者自己控制。而在Spring IOC中,这种控制权被反转,对象的创建、初始化、...
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性之一,它允许开发者将对象的创建和管理交给Spring容器来处理,从而使代码更加松耦合,更易于测试和维护。下面将详细介绍Spring IOC的基本概念、...
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性,它极大地简化了Java应用的开发,通过将对象的创建和管理交由Spring容器来处理,开发者可以更专注于业务逻辑。下面,我们将深入探讨Spring IOC...
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性,它将对象的创建和管理权交由Spring容器来负责,从而实现了依赖倒置,增强了代码的可测试性和可维护性。DI(Dependency Injection,依赖注入)...
Spring IoC,全称为Inversion of Control,即控制反转,是Spring框架的核心特性之一。它是一种设计模式,改变了传统程序中的对象创建和管理的方式,将对象的生命周期管理交由Spring容器来负责,使得代码更加解耦,...
Spring IOC,即Spring控制反转,是Spring框架的核心特性之一。控制反转(Inversion of Control,简称IoC)是一种设计原则,用于减少代码间的耦合,提高系统模块化和代码的重用性。在Spring框架中,IOC具体体现在对...
标题《Spring IoC源码深度剖析开源架构源码2021.pdf》和描述《Spring IoC源码深度剖析开源架构源码2021.pdf》表明该文档主要面向于分析Spring框架中控制反转(IoC)容器的核心源码,解析和理解其内部的工作机制及...
Java反射和Spring IOC是Java开发中的两个重要概念,它们在构建灵活、可扩展的应用程序时起着关键作用。本文将深入探讨这两个主题,并提供相关的学习资源。 首先,让我们了解一下Java反射。Java反射机制是Java语言的...
### Spring IoC与注解依赖注入详解 #### 一、Spring框架简介 Spring框架是由Rod Johnson创建的一个开源项目,最初是为了解决企业级应用开发中的复杂性问题而诞生的。Spring框架的核心特性包括IoC(Inversion of ...
在本资源"手写spring ioc(三) 资源org.zip"中,我们主要关注的是如何实现一个简易版的Spring IOC(Inversion of Control)容器,它涵盖了ioc的基本功能,包括解决循环依赖、使用构造器注入以及自动注入等核心特性。...
在Spring框架中,IOC(Inversion of Control,控制反转)是一种设计原则,它将对象的创建和管理职责从应用代码中分离出来,交由框架来处理。这样,开发者可以更专注于业务逻辑,而不是对象的生命周期。AOP(Aspect ...
springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC...
spring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demo...
**Spring 的 IoC 容器** IoC(Inversion of Control)即控制反转,是 Spring 的核心特性之一。在传统的编程模式中,对象之间存在依赖关系,程序员需要手动创建和管理这些对象。而在 Spring 中,IoC 容器负责管理和...