Spring中只有两大核心技术:IOC&DI(控制反转&依赖注入),AOP(面向切面编程)
什么是依赖注入?
利用配置文件的关系来决定类之间的引用关系以及数据的设置操作。
一.构造方法注入
默认情况下如果在applicationContext.xml文件之中配置的程序都可以自动的找到Spring容器加载时进行对象的实例化操作.但是自动进行初始化的时候调用的是类中的无参构造方法,而且通过反射机制应该知道.如果类中提供有无参构造方法一定要比有参构造方法的实例化更加容易。
1. 但是在Spring里面简化了反射的处理机制,也就是说利用Spring中的动态的特性可以直接明确调用构造方法传递参数。
范例:定义一个类
public class Dept {
private Integer deptno;
private String dname;
public Dept(Integer deptno , String dname){
this.deptno = deptno;
this.dname = dname;
}
@Override
public String toString() {
return "部门编号:"
+ this.deptno
+ ",名称"
+ this.dname;
}
}
此时类中没有提供有无参构造方法,所以配置在applicationContext.xml文件中的"<bean>"不能够正常使用,此时必须 明确调用类中的有参构造方法。
范例:application.xml配置
<bean id = "dept" class = "com.jcn.vo.Dept">
<constructor-arg value = "10"/>
<constructor-arg value = "开发部"/>
</bean>
测试类:
public class TestDept {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Dept vo = ctx.getBean("dept" , Dept.class);
System.out.println(vo);
}
}
输出结果:部门编号:10,名称开发部
2.但是在Spring的配置里面它所支持的好处远远不止这一点。如果用户有需要,也可以根据参数的索引来进行设置:
范例:修改索引操作
<bean id = "dept" class = "com.jcn.vo.Dept">
<constructor-arg index = "1" value = "开发部"/>
<constructor-arg index = "0" value = "10"/>
</bean>
虽然Spring在构造方法上考虑的还是挺多的,但是从本质上以上的索引操作并不推荐。
输出结果:部门编号:10,名称开发部
3.但是很多人会对使用索引编号的方式产生反感,认为使用参数名称描述最好了。
范例:修改Dept.java类设置参数名称
@ConstructorProperties(value = {"paramDeptno" , "paramDname"})
public Dept(Integer deptno , String dname) {
this.deptno = deptno;
this.dname = dname;
}
也就是说在设置的时候可以使用paramDeptno来代替索引0.使用paramDname来代替索引1.
范例:利用参数名称进行设置
<bean id="dept" class="com.jcn.vo.Dept">
<constructor-arg name="paramDeptno" value="10"/>
<constructor-arg name="paramDname" value="开发部"/>
</bean>
输出结果:部门编号:10,名称开发部
最终发现使用第一种方式按照参数的类型和顺序编写最为方便。
二、利用setter注入
1.在正常编写简单Java类的过程一定要提供有无参构造,甚至有许多自己定义的工具类也都会提供有无参构造,所以使用构造方法的注入操作并不是我们喜欢的方式。实际上任何的类都会通过setter设置属性,这一点在简单Java类上表现的特别明显。
范例:定义Dept类
package com.jcn.vo;
public class Dept {
private Integer deptno;
private String dname;
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "部门编号:" + this.deptno + "部门名称:" + this.dname;
}
}
2.在传统的操作之中,一定是首先定义Dept类对象,而后调用setter设置内容,但是现在可以利用Spring动态设置内容。
范例:观察spring的注入操作
<bean id = "dept" class = "com.jcn.vo.Dept">
<property name="deptno" value="10"/>
<property name="dname" value="开发部"/>
</bean>
运行结果:部门编号:10部门名称:开发部
利用这种setter的设置才是在实际开发之中使用最多的操作情况, 但是这整个利用setter注入其强大之处,还在于可以引用 其他的类型的Bean对象。
范例:定义Emp.java类
package com.jcn.vo;
public class Emp {
private Integer empno;
private String ename;
private Dept dept;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "雇员编号"
+ this.empno
+ ",姓名"
+ this.ename
+ ",部门"
+ this.dept;
}
}
下面的重点内容是在于配置文件来决定彼此的操作关系。
范例:编写applicationContext.xml
<bean id="emp" class="com.jcn.vo.Emp">
<property name="empno" value="7369"></property>
<property name="ename" value="jianzhu"></property>
<property name="dept" ref="dept"></property>
</bean>
如果现在是具体的内容则使用value属性,如果要引用其他bean的对象,那么就使用“ref”属性。
范例:测试类
public class TestEmp {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Emp vo = ctx.getBean("emp" , Emp.class);
System.out.println(vo);
}
}
运行结果:雇员编号7369,姓名jianzhu,部门部门编号:10部门名称:开发部
在最早的时候所进行的全部结构的设置过程之中都是通过程序硬编码的形式实现的,但是现在可以利用配置文件的方式,采用软编码的方式完成,所有的操作类不再需要用户负责实例化了,而全部都容器完成。
疑问?如果现在某个内容要是null怎么办呢?
现在有两种方式设置null:
方式一:不设置dname属性,内容就是null
<bean id = "dept" class = "com.jcn.vo.Dept">
<property name="deptno" value="10"/>
</bean>
运行结果:
方式二:明确的设置null
<bean id = "dept" class = "com.jcn.vo.Dept">
<property name="deptno" value="10"/>
<property name="dname" ><null/></property>
</bean>
运行结果:部门编号:10部门名称:null
方式二只是明确的告诉用户现在要设置的内容是null值。
3.但是以上所进行的属性设置只是设置了常用的类型,例如:Integer,String,其他引用,可是在实际的开发之中还有可能设置布尔值.但是对于布尔值的设置,在Spring里面支持如下几种: true\false, 1\0, on\off, yes\no
范例:设置布尔型
package com.jcn.vo;
public class Dept {
private Integer deptno;
private String dname;
private boolean close;
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public boolean isClose() {
return close;
}
public void setClose(boolean close) {
this.close = close;
}
@Override
public String toString() {
return "部门编号:" + this.deptno + "部门名称:" + this.dname;
}
}
如果在类中的属性是boolean型数据返回的时候一般都建议使用is开头,但是也可以使用get命名。
<bean id = "dept" class = "com.jcn.vo.Dept">
<property name="deptno" value="10"/>
<property name="dname" ><null/></property>
<property name="close" value="off" />
</bean>
运行结果:部门编号:10部门名称:null关闭标记:false
<property name="close" value="no" />
运行结果:部门编号:10部门名称:null关闭标记:false
三、注入集合数据
在任何开发中一定会存在集合的操作,在Spring里面也支持集合数据的注入:数组,list,map,Properties。
1.范例:注入数组数据
package com.jcn.vo;
import java.util.Arrays;
public class Company {
private String msg[];
private Integer data[];
public Integer[] getData() {
return data;
}
public void setData(Integer data[]) {
this.data = data;
}
public String[] getMsg() {
return msg;
}
public void setMsg(String msg[]) {
this.msg = msg;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "msg = " + Arrays.toString(this.msg) + "data = " + Arrays.toString(this.data);
}
}
配置applicationContext.xml文件:
<bean id="company" class="com.jcn.vo.Company">
<property name="data">
<array value-type="java.lang.Integer">
<value>10</value>
<value>20</value>
<value>30</value>
</array>
</property>
<property name="msg">
<array value-type="java.lang.String">
<value>我是</value>
<value>剑主</value>
<value>大人</value>
</array>
</property>
</bean>
在本类中可以接收两个数组的对象信息.现在可以发现,在使用数组数据的时候都设置了相应的数据类型。
测试类:
public class TestCompany {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Company vo = ctx.getBean("company" , Company.class);
System.out.println(vo);
}
}
运行结果:msg = [我是, 剑主, 大人]data = [10, 20, 30]
如果不写操作的value-type数据类型,那么Spring会自动的判断给出的数据类型,帮助用户自动转型。
但是需要清楚的是,数组一般不会再开发之中出现,如果真的出现数组了,使用List集合来横向代替数组。
2.范例:使用List集合操作
package com.jcn.vo;
import java.util.List;
public class Company {
private List<String> msg;
public List<String> getMsg() {
return msg;
}
public void setMsg(List<String> msg) {
this.msg = msg;
}
@Override
public String toString() {
return "msg = " + this.msg;
}
}
修改applicationContext.xml文件:
<bean id="company" class="com.jcn.vo.Company">
<property name="msg">
<array value-type="java.lang.String">
<value>我是</value>
<value>剑主</value>
<value>大人</value>
</array>
</property>
</bean>
运行结果:msg = [我是, 剑主, 大人]
也就是说可以得出这样一种结论:List集合 = 数组
范例:换成list集合
<bean id="company" class="com.jcn.vo.Company">
<property name="msg">
<list value-type="java.lang.String">
<value>我是</value>
<value>剑主</value>
<value>大人</value>
</list>
</property>
</bean>
运行结果:msg = [我是, 剑主, 大人]
3.范例观察set集合注入
package com.jcn.vo;
import java.util.Set;
public class Company {
private Set<String> msg;
public Set<String> getMsg() {
return msg;
}
public void setMsg(Set<String> msg) {
this.msg = msg;
}
@Override
public String toString() {
return "msg = " + this.msg;
}
}
修改applicationContext.xml文件:
<bean id="company" class="com.jcn.vo.Company">
<property name="msg">
<set value-type="java.lang.String">
<value>我是</value>
<value>剑主</value>
<value>大人</value>
</set>
</property>
</bean>
运行结果:msg = [我是, 剑主, 大人]
此时不再出现重复数据,因为set集合是不允许出现重复的。
4.范例:注入map集合
package com.jcn.vo;
import java.util.Map;
public class Company {
private Map<Integer , String> msg;
public Map<Integer , String> getMsg() {
return msg;
}
public void setMsg(Map<Integer , String> msg) {
this.msg = msg;
}
@Override
public String toString() {
return "msg = " + this.msg;
}
}
修改applicationContext.xml文件:
<bean id="company" class="com.jcn.vo.Company">
<property name="msg">
<map key-type="java.lang.Integer" value-type="java.lang.String">
<entry key="1" value="jian"></entry>
<entry key="2" value="zhu"></entry>
</map>
</property>
</bean>
运行结果:msg = {1=jian, 2=zhu}
以上的操作实际上在开发配置文件的编写过程之中见到的不多,而真正见到最多的是Properties类型。
5.范例:注入Properties
package com.jcn.vo;
import java.util.Properties;
public class Company {
private Properties msg;
public Properties getMsg() {
return msg;
}
public void setMsg(Properties msg) {
this.msg = msg;
}
@Override
public String toString() {
return "msg = " + this.msg;
}
}
Properties只能设置String型数据。
修改applicationContext.xml文件:
<bean id="company" class="com.jcn.vo.Company">
<property name="msg">
<props>
<prop key="jian">剑</prop>
<prop key="zhu">主</prop>
</props>
</property>
</bean>
运行结果:msg = {jian=剑, zhu=主}
在一些框架的集合开发之中,此类属性的设置是最为常见的。
现在所给出的实际上只是定义的一些数值,而最神奇的是它可以定义文件内部的引用关系。
6.范例:观察如下的结构
package com.jcn.vo;
public class Emp {
private Integer empno;
private String ename;
private Dept dept;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "雇员编号"
+ this.empno
+ ",姓名"
+ this.ename;
}
}
package com.jcn.vo;
import java.util.List;
public class Dept {
private Integer deptno;
private String dname;
private List<Emp> emps;
public List<Emp> getEmps() {
return emps;
}
public void setEmps(List<Emp> emps) {
this.emps = emps;
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "部门编号:" + this.deptno + "部门名称:" + this.dname ;
}
}
而后的关键就在于通过配置文件清楚的描述出以上的结构关系。
修改applicationContext.xml文件:
<bean id = "dept" class = "com.jcn.vo.Dept">
<property name="deptno" value="10"/>
<property name="dname" value="开发部" />
<property name="emps">
<list>
<ref bean="empA"/>
<ref bean="empB"/>
<ref bean="empC"/>
</list>
</property>
</bean>
<bean id="empA" class="com.jcn.vo.Emp">
<property name="empno" value="7368"></property>
<property name="ename" value="jianzhu"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="empB" class="com.jcn.vo.Emp">
<property name="empno" value="7389"></property>
<property name="ename" value="jianzhu"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="empC" class="com.jcn.vo.Emp">
<property name="empno" value="7399"></property>
<property name="ename" value="jianzhu"></property>
<property name="dept" ref="dept"></property>
</bean>
运行结果:部门编号:10部门名称:开发部雇员:[雇员编号7368,姓名jianzhu, 雇员编号7389,姓名jianzhu, 雇员编号7399,姓名jianzhu]
所有可以在程序中配置的结构关系,现在完全可以通过配置文件横向替代了。