标签:
一,spring核心概念理解
控制反转:
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。
所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
没有控制反转这种模式前,你创建一个对象,在什么地方用,你得单独通过关键字new出来用,
但现在可以不用这样,你把new对象的权利交给spring配置文件,通过配置文件来‘new‘,
在写一个程序,有多中实现方式,你如果每次都通过改程序代码,通过new来实现不同的功能,耦合性太高,
IoC是为解决松耦合而生的,以下通过代码理解。
(1)创建接口和实现类
接口:
package com.lanhuigu.spring.impl; public interface ISayHello { /** * 讲不同语言 * @return */ public String doSay(); }
说中文实现类:
package com.lanhuigu.spring.impl; public class ChHelloImpl implements ISayHello { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } /** * 讲汉语 */ @Override public String doSay() { // TODO Auto-generated method stub return "中文:"+msg; } }
说英文实现类:
package com.lanhuigu.spring.impl; public class EnHelloImpl implements ISayHello { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } /** * 讲英语 */ @Override public String doSay() { // TODO Auto-generated method stub return "英文:"+msg; } }
(2)配置spring文件
package com.lanhuigu.spring.impl; public class EnHelloImpl implements ISayHello { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } /** * 讲英语 */ @Override public String doSay() { // TODO Auto-generated method stub return "英文:"+msg; } }
(3)测试程序
package com.lanhuigu.spring.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.lanhuigu.spring.impl.ISayHello; public class TestHelloWorld { @Test public void testMyHelloWorld(){ //1.读取spring初始化的配置文件 ApplicationContext acxt = new ClassPathXmlApplicationContext("/applicationContext.xml"); //2.根据bean获取ISayHello实现类对象 ISayHello sayHello = (ISayHello) acxt.getBean("sayHello"); //3.调用接口方法 System.out.println(sayHello.doSay()); } }通过以上代码对IoC进行实例体会:
(1)在测试程序中,如果不使用IoC,你可以通过new来实现讲什么语言
ISayHello sayHello = new ChHelloImpl();//讲汉语
ISayHello sayHello = new EnHelloImpl();//讲英语
或许会觉得我就new就可以了,领导让我讲英语,我就new讲英语,领导要我讲汉语,我就讲汉语,来回注释掉就行了,
但是,如果一个应用程序中有一万个地方用到了这段代码, 你是不是得注释一万个地方,心里绝对10万个对领导不满,改来改去有病吧!
你或许还不服,我就注释掉一万个地方,如果有100万个地方呢,你是不是100万个‘草泥马‘在草原上奔腾啊!
这个时候IoC来为你解决烦恼,一剂药就能治好,再也不用担心领导让你说啥你确有苦说不出口了。
通过配置文件控制该讲什么语言:
<bean id="sayHello" class="com.lanhuigu.spring.impl.ChHelloImpl">
<!-- 将变量msg值依赖注入 -->
<property name="msg">
<value>测试</value>
</property>
</bean>
你的配置文件通过实现类配置让讲啥都行,class="com.lanhuigu.spring.impl.ChHelloImpl",
而应用代码不受影响:
ISayHello sayHello = (ISayHello) acxt.getBean("sayHello");
System.out.println(sayHello.doSay());
应用程序只管拿到的bean对象是啥,我就说啥,至于你容器怎么配置,应用程序不屌你,
而容器则配置自己的实现类,至于你应用程序实现成啥样,容器才不管,通过这样的关系
实现低耦合的实效,实现控制反转的职能。
三,依赖注入(DI)
依赖注入的含义:
让主键依赖于抽象,当组件要与其他实际对象发生关系时,通过抽象来注入依赖的实际对象。
依赖注入的三种实现方式分别是接口注入(interface injection),set方法注入(setter injection),构造注入(constructor injection)。
(1)接口注入(interface injection):
定义一个将英语的接口:
package com.lanhuigu.spring.impl; public interface ISayHello { /** * 讲英语 * @return */ public String doSay(EnHelloImpl en); }讲英语接口实现类:
package com.lanhuigu.spring.impl; public class EnHelloImpl implements ISayHello { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } /** * 讲英语 */ @Override public String doSay(EnHelloImpl en) { // TODO Auto-generated method stub return "英文:"+msg; } }如果采用接口注入的方式,原本能说各种语言的接口,被定义为只能讲英语的接口,整个业务逻辑类依赖于这个接口。
在spring中接口注入是在IOC概念没有确立时定义的,现在spring中不推荐用接口注入,接口注入业务逻辑类依赖于接口,不是重点。
(2)set方法注入(setter injection):
set注入就是指在接受注入的类中定义一个set方法,并在参数中定义需要注入的参数。
为了能够将多种语言,接口注入方式是不适用的,我们把接口定义成开放的,这样每个实现类根据需要做自己
的业务逻辑,通过set方法传入参数。
接口:
package com.lanhuigu.spring.impl; public interface ISayHello { /** * 讲不同语言 * @return */ public String doSay(); }
实现类:
汉语实现类:
package com.lanhuigu.spring.impl; public class ChHelloImpl implements ISayHello { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } /** * 讲汉语 */ @Override public String doSay() { // TODO Auto-generated method stub return "中文:"+msg; } }
英语实现类:
package com.lanhuigu.spring.impl; public class EnHelloImpl implements ISayHello { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } /** * 讲英语 */ @Override public String doSay() { // TODO Auto-generated method stub return "英文:"+msg; } }配置文件传入参数:
<?xml version="1.0" encoding="UTF-8"?> <!-- - Application context definition for JPetStore's business layer. - Contains bean references to the transaction manager and to the DAOs in - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation"). --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- 定义一个id为sayHello的bean, 通过spring配置文件变换实现类,实现不同的功能,无需修改别的程序 --> <bean id="sayHello" class="com.lanhuigu.spring.impl.ChHelloImpl"> <!-- 将变量msg值依赖注入 --> <property name="msg"> <value>测试</value> </property> </bean> </beans>每一个接口实现类对应一种逻辑,spring配置文件负责调配。
配置文件bean的property有个默认属性name,这个name对应的是bean的class类对象中的属性名msg,
代码样式private String msg,value为属性值,通过类中的set方法,将配置文件中的属性值注入,
在类中通过get获取属性值。
(3)构造注入(constructor injection):
构造注入就是在接受注入的类中定义一个构造方法,并在参数中定义需要注入的元素。
咱们将讲英语改成构造方法注入:
接口:
package com.lanhuigu.spring.impl; public interface ISayHello { /** * 讲不同语言 * @return */ public String doSay(); }实现类:
package com.lanhuigu.spring.impl; public class ChHelloImpl implements ISayHello { private String msg; private String two; /** * 构造方法注入 * @param msg * @param two */ public ChHelloImpl(String msg,String two){ this.msg = msg; this.two = two; } /*public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; }*/ /** * 讲汉语 */ @Override public String doSay() { // TODO Auto-generated method stub return "中文:"+msg+two; } }spring配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!-- - Application context definition for JPetStore's business layer. - Contains bean references to the transaction manager and to the DAOs in - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation"). --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- 定义一个id为sayHello的bean, 通过spring配置文件变换实现类,实现不同的功能,无需修改别的程序 --> <bean id="sayHello" class="com.lanhuigu.spring.impl.ChHelloImpl"> <!-- 将变量msg值依赖注入 --> <!-- <property name="msg"> <value>测试</value> </property> --> <!-- 构造放入注入, 如果不写index,默认构造方法只有一个参数, 如果注入多个,就会报错; 如果注入多个参数,可以通过index的下标指定与构造方法参数的对应关系, 下标从0开始,0表示构造方法的第一个参数,依次类推 --> <constructor-arg index="0"> <value>测试</value> </constructor-arg> <constructor-arg index="1"> <value>two arg</value> </constructor-arg> </bean> </beans>测试程序:
package com.lanhuigu.spring.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.lanhuigu.spring.impl.ISayHello; public class TestHelloWorld { @Test public void testMyHelloWorld(){ //1.读取spring初始化的配置文件 ApplicationContext acxt = new ClassPathXmlApplicationContext("/applicationContext.xml"); //2.根据bean获取ISayHello实现类对象 ISayHello sayHello = (ISayHello) acxt.getBean("sayHello"); //3.调用接口方法 System.out.println(sayHello.doSay()); } }输出结果:
中文:测试two arg
关于构造方法注入的注意点:
(1)在接受注入的构造方法中写需要注入的参数
(2)配置文件中构造属性constructor-arg不写index时默认一个参数,如果构造方法有多个参数,将报错
(3)如果注入多个参数,需在配置文件中constructor-arg通过index明确value对应构造方法中的参数情况
四,总结
依赖注入有三种注入方式,到底哪种注入方式好,一般推荐使用set注入
接口注入不考虑,构造方法注入通过上面的实例可以看出,如果注入参数太多,
构造方法中就会有一堆参数,看着都迷糊,而spring配置文件还得对参数做对应的传值,
如果注入类太多,参数太多,构造器配置越多,就会迷糊;
而set则是根据名字注入,能够避免构造方法注入的麻烦,但是,使用set方法注入是动态的注入参数,
可能被人篡改,构造方法注入在类启动时就完成,就不会出现篡改的可能,相对安全性高,二者各有
千秋,但是通常用set注入,构造方法注入酌情处理。
来注入的,这一点比构造方法注入好
spring(3)------控制反转(IOC)/依赖注入(DI)
标签:
原文地址:http://blog.csdn.net/yhl_jxy/article/details/50988543