Spring简单介绍
——以及IOC容器和Bean的配置
Spring简介
Spring是一个开源的框架,也是一个IOC和AOP容器框架。
Sprin特点
①非侵入式:基于Spring开发的应用中的对象可以不依赖与Spring的API。
②依赖注入:DI—Dependency Injection,反转控制(IOC)最经典的实现。
③面向切面编程:Aspect Oriented Programming——AOP。
④容器:Spring是一个容器,因为它包含并且管理应用对象的声明周期。
⑤组件化:Spring实现了使用简单组件配置组合成一个复杂的应用,在Spring中可以使用XML和Java注解组合这些对象。
⑥一站式:在IOC和AOP的基础上可以整合各种企业应用开源框架和优秀的第三方类库。
Spring模块
搭建Spring运行时环境
- 加入JAR包(五个jar必须先导入)
① Spring自身JAR包:spring-framework-4.0.0.RELEASE\libs目录下
- spring-beans-4.0.0.RELEASE.jar
- spring-context-4.0.0.RELE2ASE.jar
- spring-core-4.0.0.RELEASE.jar
- spring-expression-4.0.0.RELEASE.jar
② commons-logging-1.1.1.jar
- 在Spring Tool Suite工具中通过如下步骤创建Spring的配置文件
① File->New->Spring Bean Configuration File
② 为文件取名字 例如:applicationContext.xml
IOC容器
IOC(Inversion of Control):反转控制,IOC容器在最底层实质上就是一个对象工厂。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
DI(Dependency Injection):依赖注入
IOC 就是一种反转控制的思想, 而DI是对IOC的一种具体实现。
IOC容器在Spring中的实现
1)在通过IOC容器读取Bean的’实例之前,需要先将IOC容器本身实例化。
2)Spring提供了IOC容器的两种实现方式
① BeanFactory:IOC容器的基本实现,是Spring内部的基础设施,是面向Spring本身的,不是提供给开发人员使用的。
② ApplicationContext:BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。
ApplicationContext的主要实现类
-
ClassPathXmlApplicationContext:对应类路径下的XML格式的配置文件
-
FileSystemXmlApplicationContext:对应文件系统中的XML格式的配置文件
-
在初始化时就创建单例的bean,也可以通过配置的方式指定创建的Bean是多实例的。
bean的属性赋值
(1)依赖注入的方式
A.通过bean的setXxx()方法赋值(最常用)
创建一个Employee类
package bean;
public class Employee {
private Integer id;
private String name;
private String desc;
public Employee(Integer id, String name, String desc) {
super();
this.id = id;
this.name = name;
this.desc = desc;
}
public Employee() {
super();
System.out.println("无参构造器被调用了");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
System.out.println("setId");
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("setName");
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
System.out.println("setDesc");
this.desc = desc;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", desc=" + desc + "]";
}
}
创建配置文件XML
<bean id="employee01" class="bean.Employee">
<!--name="xxx"中的xxx不是随便设置的,就是将bean.Employee中setXxx()方法名都变为小写,比如xxx,value的值是自己设置的,类似于构造器初始化设置的值。-->
<property name="id" value="1001" ></property>
<property name="name" value="张三" ></property>
<property name="desc" value="好人1" ></property>
</bean>
创建测试类
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import bean.Employee;
public class Test01 {
public static void main(String[] args) {
/*创建Spring容器对象,在创建容器对象的时候,会读取spring的配置文件,从配置文件中,可以知道, 当前容器管理了那些对象的创建,同时会将容器所管理的对象给创建出来。*/
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
// 从Spring容器对象中获取员工
Employee employee = context.getBean("employee01", Employee.class);
System.out.println(employee);
}
执行结果:
无参构造器被调用了
setId
setName
setDesc
Employee [id=1001, name=张三, desc=好人1]
B.通过bean的构造器赋值(了解)
1) 按照构造函数中的参数名字进行匹配
Employee类中其他都不变,有参构造变为如下:
public Employee(Integer id, String name, String desc) {
super();
System.out.println("有参构造被调用了");
this.id = id;
this.name = name;
this.desc = desc;
}
配置文件XML改为如下:
<bean id="employee02" class="bean.Employee">
<constructor-arg name="id" value="1002"></constructor-arg>
<constructor-arg name="name" value="李四"></constructor-arg>
<constructor-arg name="desc" value="好人2"></constructor-arg>
</bean>
执行结果:
有参构造被调用了//此时不调用set()方法
Employee [id=1002, name=李四, desc=好人2]
2) 通过索引值指定参数位置
Employee类不变,只是改变一下配置文件:
<bean id="employee03" class="bean.Employee">
<constructor-arg index="0" value="1003"></constructor-arg>
<constructor-arg index="1" value="王五"></constructor-arg>
<constructor-arg index="2" value="好人3"></constructor-arg>
</bean>
执行结果:
有参构造被调用了
Employee [id=1003, name=王五, desc=好人3]
3) Spring自动匹配合适的构造器
自动匹配合适的构造器,要求传递的参数类型必须和构造函数形参类型一致!
Employee类不变,只是改变一下配置文件:
<bean id="employee04" class="bean.Employee">
<constructor-arg value="1004"></constructor-arg>
<constructor-arg value="钱六"></constructor-arg>
<constructor-arg value="好人4"></constructor-arg>
</bean>
执行结果:
有参构造被调用了
Employee [id=1004, name=钱六, desc=好人4]
4) 通过类型区分重载的构造器
在Employee类中添加Double类型的salary属性,其他属性不改变,并提供get/set方法,和toString方法,提供新的构造函数,这个构造函数不需要desc。
package bean;
public class Employee {
private Integer id;
private String name;
private String desc;
private Double salary;
public Employee(Integer id, String name, String desc) {
super();
this.id = id;
this.name = name;
this.desc = desc;
}
public Employee(Integer id, String name, Double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
public Employee() {
super();
// TODO Auto-generated constructor stub
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", desc=" + desc + ", salary=" + salary + "]";
}
}
改变一下配置文件:
<bean id="employee05" class="bean.Employee">
<constructor-arg value="1005"></constructor-arg>
<constructor-arg value="冯7"></constructor-arg>
<constructor-arg value="10000"></constructor-arg>
</bean>
执行结果
Employee [id=1005, name=冯7, desc=10000, salary=null]//当有两个构造器时,前面应该调用接收String类型的构造函数,也调用接收Double类型参数的构造器,原因是反射底层在获取类中所有构造方法的时候,放到了一个数组中,如果数组中的第一个可以匹配,那么后面的就不在匹配了。
遍历构造器:
public static void main(String[] args){
testConstructor();
}
public static void testConstructor() {
Class cla = Employee.class;
Constructor[] cons = cla.getDeclaredConstructors();
for (Constructor constructor : cons) {
System.out.println(constructor);
}
}
结果如下:
public bean.Employee(java.lang.Integer,java.lang.String,java.lang.String)
public bean.Employee(java.lang.Integer,java.lang.String,java.lang.Double)
public bean.Employee()
问题的解决:在xml文件中设置type
<bean id="employee05" class="bean.Employee">
<constructor-arg value="1005"></constructor-arg>
<constructor-arg value="冯7"></constructor-arg>
<constructor-arg value="10000" type="java.lang.Double"></constructor-arg>
</bean>
结果如下:
Employee [id=1006, name=冯七,salary=10000.0]
字面值
-
可以使用字符串表示的值,可以通过value属性或value子节点的方式指定。
-
基本数据类型及其封装类、String等类型都可以采取字面值注入的方式
-
若字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来
创建一个Book类
package bean;
public class Book {
private String isbn;
private String name;
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Book [isbn=" + isbn + ", name=" + name + "]";
}
}
在spring_ioc.xml文件中进行配置
<bean id="book01" class="bean.Book">
<!--通过value属性赋值-->
<property name="isbn" value="j001"></property>
<property name="name" value="活着"></property>
</bean>
-------------------------------------------------------------------------------------
<bean id="book02" class="bean.Book">
<!--通过value标签赋值-->
<property name="isbn">
<value>j001</value>
</property>
<property name="name">
<value>活着</value>
</property>
</bean>
-------------------------------------------------------------
<bean id="book03" class="bean.Book">
<!--通过value标签赋值,可以省略标签体,直接以“/”结束-->
<property name="isbn" value="j001"/>
<property name="name" value="活着"/>
</bean>
<!--如果有特殊的字符可以使用实体转义,也可以放在<![CDATA[]]中,<![CDATA[]]不能使用value属性,只能使用value标签-->
<property name="name">
<value>
<![CDATA[!@#!编程思想]]>
</value>
</property>
引用其他的bean
创建员工类Employee和部门类Department
package bean;
public class Employee {
private Integer id;
private String name;
private String desc;
private Double salary;
private Department dept;
public Employee(Integer id, String name, String desc, Double salary, Department dept) {
super();
this.id = id;
this.name = name;
this.desc = desc;
this.salary = salary;
this.dept = dept;
}
public Employee() {
super();
// TODO Auto-generated constructor stub
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", desc=" + desc + ", salary=" + salary + ", dept=" + dept
+ "]";
}
}
package bean;
public class Department {
private Integer id;
private String name;
public Department() {
super();
// TODO Auto-generated constructor stub
}
public Department(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}
在12.xml文件中配置部门属性
<bean id="employee01" class="bean.Employee">
<property name="id" value="1006"></property>
<property name="name" value="张三丰"></property>
<property name="desc" value="员工"></property>
<property name="salary" value="1500"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="bean.Department">
<property name="id" value="200"></property>
<property name="name" value="武当山"></property>
</bean>
</beans>
测试类
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import bean.Employee;
public class Test03 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("12.xml");
Employee employee01 = context.getBean("employee01", Employee.class);
System.out.println(employee01);
}
}
结果:
Employee [id=1006, name=张三丰, desc=员工, salary=1500.0, dept=Department [id=200, name=武当山]]
给bean的级联属性赋值
<bean id="employee02" class="bean.Employee">
<property name="id" value="1007"></property>
<property name="name" value="张丰"></property>
<property name="desc" value="员工02"></property>
<property name="salary" value="15002"></property>
<property name="dept" ref="dept"></property>
<!--级联属性操作-->
<property name="dept.name" value="峨眉派"></property>
</bean>
<bean id="dept" class="bean.Department">
<property name="id" value="200"></property>
<property name="name" value="武当山"></property>
</bean>
结果:
Employee [id=1007, name=张丰, desc=员工02, salary=15002.0, dept=Department [id=200, name=峨眉派]]