一、Spring的相关概念
1.Spring是开源的轻量级框架
2.Spring核心主要两部分:
(1)aop:面向切面编程,扩展功能不是修改源代码实现。
(2)ioc:控制反转。
例如有一个类,在类里面有个方法(不是静态的方法),调用类里面的方法,创建类的对象,使用对象调用方法,创建类对象的过程,需要new出来对象。
3.Spring是一站式框架
(1)Spring在javaee三层结构中,每一层都提供不同的解决技术
web层:SpringMVC
service层:Spring的ioc
dao层:Spring的jdbc Template
二、Spring的IOC的底层原理
1.漏洞百出的过去
使用创建对象来调用一个类中的方法:
public class User {
public void add() {
...
}
}
// 在Servlet调用User类里面的方法
// 调用类里面的方法
User user = new User();
user.add();
缺陷:耦合度太高
针对上面的缺陷,于是产生了工厂模式来进行解耦合操作:
public class UserService {
public void add() {
...
}
}
public class UserServlet {
UserService s = Factory.getService();
s.add();
}
// 创建工厂类
public class Factory {
public static UserService getService() {
return new UserService();
}
}
上述的代码缺陷就是UserServlet与工厂类进行耦合。
2.IOC的原理
public class UserService {
public void add() {
...
}
}
public classUserServlet {
// 得到UserService的对象
// 原始:new创建
UserService s = UserFactory.getService();
s.add();
}
第一步:创建xml配置文件,配置需要创建
<!-- 对象类 -->
<bean id="userService" class="com.jxs.UserService"/>
第二步:创建工厂类,使用dom4j解析配置文件+反射
// 返回UserService对象的方法
public static UserService getService() {
// 1.使用dom4j解析xml文件
// 根据id值userService,得到id值对应class属性值(类的全路径)
String classValue = "class属性值";
// 2.使用反射创建类对象
Class clazz = Class.forName(classValue);
// 3.创建类对象
UserService service = clazz.newInstance();
return service;
}
这样即使UserService类的路径发生了变化也不会对程序造成影响,从而降低了类之间的耦合度。
三、Spring的bean管理(xml配置文件)
1.bean实例化
在Spring中通过配置文件创建对象
2.bean实例化三种样式
(1)使用类的无参数构造创建(重要)
package com.jxs.ioc;
/**
* Created by jiangxs on 2018/3/26.
*/
public class Bean {
public void show() {
System.out.println("hello!");
}
}
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 使用类的无参数构造创建 -->
<bean id="bean" class="com.jxs.ioc.Bean"></bean>
</beans>
当类中没有无参数的构造时,就会出现异常。
(2)使用静态工厂创建
创建静态的方法,返回类对象
package com.jxs.ioc;
/**
* Created by jiangxs on 2018/3/26.
*/
public class BeanStaticFactory {
public static Bean getBean() {
return new 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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 使用静态工厂创建对象 -->
<bean id="bean2" class="com.jxs.ioc.BeanStaticFactory" factory-method="getBean"></bean>
</beans>
(3)使用实例工厂创建
创建不是静态的方法,返回类对象
package com.jxs.ioc;
/**
* Created by jiangxs on 2018/3/26.
*/
public class BeanStaticFactory {
public Bean getBean() {
return new 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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 使用实例工厂创建对象 -->
<bean id="beanStaticFactory" class="com.jxs.ioc.BeanStaticFactory"></bean>
<bean id="bean" class="com.jxs.ioc.BeanStaticFactory" factory-method="getBean"></bean>
</beans>
2.bean标签常用属性
(1)id属性:
起名称,id属性值名称可以任意命名,但是id属性值不能包含特殊符号,例如:!@#$%^&*()_等等,根据id值可以获得配置对象。
(2)class属性:
创建对象所在类的全路径
(3)name属性:
功能和id属性一样。id属性值不能包含特殊符号,但是在name属性值里面可以包含特殊符号,其区别是name属性主要是用于解决一些带符号的命名的遗留问题,现在一般使用id属性。
(4)scope属性
singleton:默认值,对象是单例
prototype:多例
request:创建对象,把对象放到request域里面
session:创建对象,把对象放到session域里面
globalSession:创建对象,把对象放到globalSession域里面
3.属性注入方式
(1)属性注入就是在创建对象的时候向类里面设置值
(2)属性注入的方式介绍(三种方式)
第一种:使用set方法注入
class User {
private String name;
public void setName(String name) {
this.name = name;
}
}
public class Main {
User user = new User();
user.setName("abcd");
}
第二种:有参数构造器注入
class User {
private String name;
public User (String name) {
this.name = name;
}
}
public class Main {
User user = new User("abcd");
}
第三种:使用接口注入
public interface Dao {
public void delete(String name);
}
public class DaoImpl implements Dao {
private String name;
public void delete(String name) {
this.name = name;
}
}
在Spring框架中,只支持前两种属性注入的方式:
(1)使用set方法注入(重点)
使用set进行属性注入代码示例:
package com.jxs.ioc;
/**
* Created by jiangxs on 2018/3/27.
*/
public class PropertyDemo2 {
private String userName;
public void setUserName(String userName) {
this.userName = userName;
}
public void print() {
System.out.println(userName);
}
}
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 使用set方法注入属性-->
<bean id="demo2" class="com.jxs.ioc.PropertyDemo2">
<!-- 注入属性值
name属性值:类里面定义的属性名称
value属性:设置具体的值-->
<property name="userName" value="hello!!!">
</property>
</bean>
</beans>
(2)有参数构造器注入
有参数构造器进行属性注入代码示例:
package com.jxs.ioc;
/**
* Created by jiangxs on 2018/3/26.
*/
public class PropertyDemo1 {
private String userName;
public PropertyDemo1(String userName) {
this.userName = userName;
}
public void print() {
System.out.println("hhhh" + userName);
}
}
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 使用有参数构造注入属性 -->
<bean id="demo1" class="com.jxs.ioc.PropertyDemo1">
<!-- 使用有参构造注入 -->
<constructor-arg name="userName" value="wsjxsa">
</constructor-arg>
</bean>
</beans>
4.注入对象类型属性
以下列代码为例进行说明(在UserService类中得到UserDao的对象)
实现过程:
(1)在UserService里面把UserDao作为类型属性
(2)生成UserDao类型属性的set方法
package com.jxs.ioc;
/**
* Created by jiangxs on 2018/3/27.
*/
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("This is Service add operation");
// UserDao dao = new UserDao();
// dao.add();
userDao.add();
}
}
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 使用set方法注入对象类型属性-->
<bean id="userDao" class="com.jxs.ioc.UserDao"></bean>
<bean id="userService" class="com.jxs.ioc.UserService">
<!-- 注入dao对象
name属性值:UserService类中属性名称
不写value属性,因为此时的类型是一个对象
ref属性值:UserDao配置bean标签中的id值-->
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
5.P名称空间注入
代码示例:
package com.jxs.ioc;
/**
* Created by jiangxs on 2018/3/27.
*/
public class Person {
private String personName;
public void setPersonName(String personName) {
this.personName = personName;
}
public void print() {
System.out.println("name is "+personName);
}
}
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- p名称空间注入 -->
<bean id="person" class="com.jxs.ioc.Person" p:personName="jxs"></bean>
</beans>
测试代码:
package com.jxs.ioc;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by jiangxs on 2018/3/26.
*/
public class TestIOC {
@Test
public void testPerson() {
// 1.加载Spring配置文件,根据配置文件的配置创建对象
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 2.得到配置创建对象
Person person = (Person) context.getBean("person");
person.print();
}
}
测试结果:
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
name is jxs
Process finished with exit code 0
6.注入复杂类型
(1)数组
(2)list集合
(3)map集合
(4)properties类型
代码示例:
package com.jxs.ioc;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* Created by jiangxs on 2018/3/27.
*/
public class Person {
private String personName;
private String[] arrays;
private List<String> list;
private Map<String, Integer> map;
private Properties properties;
public void setArrays(String[] arrays) {
this.arrays = arrays;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, Integer> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setPersonName(String personName) {
this.personName = personName;
}
public void printComplex() {
System.out.println("arrays:"+arrays);
System.out.println("list:"+list);
System.out.println("map:"+map);
System.out.println("properties:"+properties);
}
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注入复杂类型属性值 -->
<bean id="person" class="com.jxs.ioc.Person">
<!-- 数组 -->
<property name="arrays">
<list>
<value>jxs</value>
<value>哈哈</value>
<value>2018-3-27</value>
</list>
</property>
<!-- list集合 -->
<property name="list">
<list>
<value>这是</value>
<value>集合</value>
</list>
</property>
<!-- map集合 -->
<property name="map">
<map>
<entry key="jxs" value="10"/>
<entry key="jmf" value="11"/>
<entry key="wrq" value="1"/>
</map>
</property>
<!-- properties -->
<property name="properties">
<props>
<prop key="url">com.mysql.jdbc.Driver</prop>
<prop key="username">root</prop>
<prop key="psaaword">root</prop>
</props>
</property>
</bean>
</beans>
测试代码:
package com.jxs.ioc;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by jiangxs on 2018/3/26.
*/
public class TestIOC {
@Test
public void testPerson() {
// 1.加载Spring配置文件,根据配置文件的配置创建对象
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 2.得到配置创建对象
Person person = (Person) context.getBean("person");
person.printComplex();
}
}
测试结果:
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
arrays:[Ljava.lang.String;@31f924f5
list:[这是, 集合]
map:{jxs=10, jmf=11, wrq=1}
properties{url=com.mysql.jdbc.Driver, psaaword=root, username=root}
7.IOC和DI的区别
(1)IOC:控制反转,把对象创建交给Spring进行配置。其思想是反转资源获取的方向。IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
传统的资源查找要求组件向发起请求查找资源,作为回应,容器适时的返回资源,而应用了IoC之后,则是容器主动将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源,这种行为也被称为查找的被动形式。
(2)DI:依赖注入,向类里面的属性中设置值IOC的另一种表述方式:即组件以一些预先定义好的方式(如:setter方法)接受来自容器的资源注入。相对于IOC而言,这种表述更为直接。
关系:依赖注入不能单独存在,需要在IOC的基础之上完成操作。依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。
四、Spring整合Web项目原理
1.加载Spring核心配置文件
// 加载Spring核心配置文件,根据配置文件的配置创建对象
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
这种new对象的方式,功能上可以实现,但是效率很低
2.实现思想
把加载配置文件和创建对象的过程在服务器启动时完成
3.实现原理
(1)ServletContext对象
(2)监听器
(3)具体使用:
- 在服务器启动的时候,为每个项目创建一个ServletContext对象
- 在ServletContext对象创建的时候,使用监听器可以具体到ServletContext对象在什么时候创建(监听器ServletContextListener的contextInitialized()方法会执行,ServletContext对象会创建,然后放入ServletContext的对象中)
- 使用监听器监听到ServletContext对象创建的时候,加载Spring配置文件,把配置文件配置的对象进行创建
- 把创建出来的对象放到ServletContext域里面(setAttribute方法)
- 获取对象的时候,到ServletContext域得到(getAttribute方法)