一、spring框架概述
spring是一个开源免费的框架,是基于java平台为了解决企业应用开发的复杂性而创建的。spring是各个功能是模块化的,所以你不使用的功能可以舍弃掉,只使用其中的部分功能。
1、spring是一款轻量级的企业级框架,所以不需要你实现或继承spring中的接口和类,各个逻辑代码不依赖于spring框架本身,你可以只专注于本身本身,所以你可以很轻松的把spring分离开来。
2、控制反转IOC(Inversion of Control):是一种设计思想,反转资源获取的方向,通过依赖注入DI(Dependency Injection)的方式来实现;传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式,使用IOC时,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象;即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入.
3、面向切面AOP(Aspect-Oriented Programming,面向方面编程):
二、spring的组成
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是
BeanFactory
,它是工厂模式的实现。BeanFactory
使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。 - Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
三、IOC容器
IOC:Inversion of Control,控制反转。指的是对象的创建权反转(交给)给Spring,其作用是实现了程序的解耦合。也可这样解释:获取对象的方式变了。对象创建的控制权不是“使用者”,而是“框架”或者“容器”。 用更通俗的话来说,IOC就是指对象的创建,并不是在代码中用new操作new出来的,而是通过Spring进行配置创建的。其底层实现原理是XML配置文件+SAX解析+工厂设计模式。
(一)使用xml配置的方式来实现IOC
IUserDao.java:
package com.test.spring01;
public interface IUserDao {
/**
* 添加用户
*/
public void addUser();
}
UserDao.java
package com.test.spring01;
public class UserDao implements IUserDao{
@Override
public void addUser() {
System.out.println("添加了一个用户");
}
}
applicationContext.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:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<bean id="userDao" class="com.test.spring01.UserDao"></bean>
</beans>
main.java
package com.test.spring01;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
@Test
public void test1() {
//获取IOC容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中获取userDao
IUserDao userDao = (IUserDao) applicationContext.getBean("userDao");
//调用业务方法
userDao.addUser();
}
}
运行结果:
1.通过有参构造函数与setting的方式创建对象
Employee.java
package com.test.spring02;
public class Employee {
private String name;
private String sex;
private Double salary;
private Department dept;
public Employee() {
super();
}
public Employee(String name, String sex, Double salary, Department dept) {
super();
this.name = name;
this.sex = sex;
this.salary = salary;
this.dept = dept;
}
//此处省略getter与setter方法
@Override
public String toString() {
return "Employee [name=" + name + ", sex=" + sex + ", salary=" + salary + ", dept=" + dept + "]";
}
}
Department.java
package com.test.spring02;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Department {
private String name;
private String deptno;
private List<Employee> list;
private Set<Employee> set;
private Map<String, Employee> map;
public Department() {
super();
}
public Department(String name, String deptno) {
super();
this.name = name;
this.deptno = deptno;
}
public Department(String name, String deptno, List<Employee> list, Set<Employee> set, Map<String, Employee> map) {
super();
this.name = name;
this.deptno = deptno;
this.list = list;
this.set = set;
this.map = map;
}
//此处省略getter与setter方法
@Override
public String toString() {
return "Department [name=" + name + ", deptno=" + deptno + "]";
}
}
applicationContext.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:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 1、根据构造器参数的类型 -->
<bean id="employee1" class="com.test.spring02.Employee">
<constructor-arg type="java.lang.String" value="张三" />
<constructor-arg type="java.lang.String" value="男" />
<constructor-arg type="java.lang.Double" value="100.0" />
<constructor-arg type="com.test.spring02.Department" ref="dept" />
</bean>
<!-- 2、根据索引index注入 -->
<bean id="employee2" class="com.test.spring02.Employee">
<constructor-arg index="0" value="李四" />
<constructor-arg index="1" value="女" />
<constructor-arg index="2" value="100.0" />
<constructor-arg index="3" ref="dept" />
</bean>
<!-- 3、根据参数名称注入 -->
<bean id="employee3" class="com.test.spring02.Employee">
<constructor-arg name="name" value="王五" />
<constructor-arg name="sex" value="男" />
<constructor-arg name="salary" value="100.0" />
<constructor-arg name="dept" ref="dept" />
</bean>
<!-- 4、根据setting的方式注入 -->
<bean id="dept" class="com.test.spring02.Department">
<property name="name" value="人事部" />
<property name="deptno" value="0x0001" />
</bean>
<!-- 5.使用内部bean的方式注入 -->
<bean id="employee4" class="com.test.spring02.Employee">
<property name="name" value="赵六"></property>
<property name="sex" value="男"></property>
<property name="salary" value="100.0"></property>
<property name="dept">
<!-- 只能在内部使用,可以不写id值 -->
<bean id="dept" class="com.test.spring02.Department">
<property name="name" value="人事部" />
<property name="deptno" value="0x0001" />
</bean>
</property>
</bean>
<!-- 6.使用级联的方式注入 -->
<bean id="employee5" class="com.test.spring02.Employee">
<property name="name" value="陈七"></property>
<property name="sex" value="男"></property>
<property name="salary" value="100.0"></property>
<property name="dept">
<bean id="dept" class="com.test.spring02.Department">
<property name="name" value="人事部" />
</bean>
</property>
<!-- 级联属性赋值,注意:属性需要先初始化后才可以为级联属性赋值,否为会有异常 -->
<property name="dept.deptno" value="0x00001"></property>
</bean>
<!-- 通过p命名空间为bean的属性赋值,需导入p命名空间 -->
<bean id="employee6" class="com.test.spring02.Employee" p:name="吴八" p:sex="男" p:salary="100.0" p:dept-ref="dept"></bean>
<!-- 7.注入集合属性 -->
<bean id="dept2" class="com.test.spring02.Department">
<property name="name" value="人事部" />
<property name="deptno" value="0x0001" />
<!-- 注入list集合 -->
<property name="list">
<list>
<ref bean="employee1"/>
<bean id="employee3" class="com.test.spring02.Employee">
<constructor-arg name="name" value="王五" />
<constructor-arg name="sex" value="男" />
<constructor-arg name="salary" value="100.0" />
<constructor-arg name="dept" ref="dept" />
</bean>
</list>
</property>
<!-- 注入set集合 -->
<property name="set" ref="set"></property>
<!-- 注入map集合 -->
<property name="map">
<map>
<entry key="emp1" value-ref="employee1"></entry>
<entry key="emp2" value-ref="employee2"></entry>
</map>
</property>
</bean>
<!-- 配置单例的集合bean,以供多个bean进行引用,需要导入util命名空间 -->
<util:set id="set">
<ref bean="employee1"/>
<ref bean="employee2"/>
</util:set>
</beans>
Main.java
package com.test.spring01;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.test.spring02.Department;
import com.test.spring02.Employee;
public class Main {
@Test
public void test2() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Employee employee1 = (Employee) applicationContext.getBean("employee1");
Employee employee2 = (Employee) applicationContext.getBean("employee2");
Employee employee3 = (Employee) applicationContext.getBean("employee3");
Employee employee4 = (Employee) applicationContext.getBean("employee4");
Employee employee5 = (Employee) applicationContext.getBean("employee5");
Employee employee6 = (Employee) applicationContext.getBean("employee6");
Department dept2 = (Department)applicationContext.getBean("dept2");
System.out.println(employee1);
System.out.println(employee2);
System.out.println(employee3);
System.out.println(employee4);
System.out.println(employee5);
System.out.println(employee6);
System.out.println(dept2 +" list: "+ dept2.getList());
System.out.println(dept2 +" set: "+ dept2.getSet());
System.out.println(dept2 +" map: "+ dept2.getMap());
}
}
运行结果:
注意事项:
- bean中的id为唯一标识,不可重复
- 使用构造函数的方式创建对象,对应的类中需要有对应的构造函数
- 若字面值中包含特殊字符, 则可以使用 DCDATA 来进行赋值. (![CDATA[<ATARZA>])
- 如果要为一个属性赋值为null,可以使用<null/>进行赋值
- 若一个 bean 有多个构造器,可以根据 index 和 value 进行更加精确的定位
- 级联属性赋值时先初始化后才可以为级联属性赋值,否为会报空指针异常
2.通过工厂方法创建对象
- 通过静态工厂方法创建对象
User.java
package com.test.spring06;
public class User {
private String name;
private int age;
public User() {
super();
}
public User(String name, int age) {
super();
this.name = name;
this.age = age;
}
//此处省略getter与setter方法
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
StaticUserFactory.java
package com.test.spring06;
import java.util.HashMap;
import java.util.Map;
public class StaticUserFactory {
private static Map<String, User> users = new HashMap<String, User>();
static {
users.put("Jack",new User("Jack",17));
users.put("Rose",new User("Rose",17));
}
public static User getUser(String name) {
return users.get(name);
}
}
applicationContext-factory.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:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 通过静态工厂方法来配置bean -->
<!--
class 属性:只想静态工厂方法的全类名
factory-method:指向静态工厂方法的方法名
constructor-arg:静态工厂方法需要传入参数
-->
<bean id="user" class="com.test.spring06.StaticUserFactory" factory-method="getUser">
<constructor-arg value="Jack"></constructor-arg>
</bean>
</beans>
Main.java
package com.test.spring06;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-factory.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
得到结果:
- 通过实例工厂方法获取对象
User.java
package com.test.spring06;
public class User {
private String name;
private int age;
public User() {
super();
}
public User(String name, int age) {
super();
this.name = name;
this.age = age;
}
//此处省略getter与setter方法
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
InstanceUserFactory.java
package com.test.spring06;
import java.util.HashMap;
import java.util.Map;
public class InstanceUserFactory {
private Map<String, User> users;
public InstanceUserFactory() {
users = new HashMap<String, User>();
users.put("Jack",new User("Jack",17));
users.put("Rose",new User("Rose",17));
}
public User getUser(String name) {
return users.get(name);
}
}
applicationContext-factory.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:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 配置工厂的实例 -->
<bean id="userFactory" class="com.test.spring06.InstanceUserFactory"></bean>
<!-- 通过实例公共方法来配置bean -->
<bean id="user" factory-bean="userFactory" factory-method="getUser">
<constructor-arg value="Rose"></constructor-arg>
</bean>
</beans>
Main.java
package com.test.spring06;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-factory.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
得到结果: