Spring是位于service层的框架, 有很多的优点。 其中它有两个核心IOC + AOP
IOC
Inversion Of Control 翻译过来是控制反转的意思。 说得通俗一点, 就是把对象的创建工作交给spring。
UserService userService = new UserServiceImpl(); userService.save();
AOP
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程. 在不改动源码的前提下,对原有的功能进行扩展与增强。
二、 IOC 演变过程
早期的演变过程
工厂的演变过程
三、Spring入门
导入jar包
core | beans | context | expression
导入4个日志包
创建业务逻辑类
public class UserServiceImpl implements UserService {
@Override public void save() { System.out.println("调用UserServiceImpl的save方法!~~~"); } }
在src下面新建一个xml文件,名字为applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 1. 导入约束 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="us" class="com.itheima.service.impl.UserServiceImpl"></bean> </beans>
创建工厂,问工厂要实例对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //2. 问工厂要对象 UserService userService = (UserService) context.getBean("us"); userService.save();
四、配置详解
1. xml配置解释
<!-- 使用bean标签来表示,需要spring托管的具体类, 也就是让spring帮忙创建谁的实例,就用bean来说明它
id | name : 标识符 、唯一值。
class : 托管的类全路径
默认生成的实例是单例。
scope一般不写,如果要做成多实例,那么里面就需要换成prototype
init-method="init" destroy-method="destory" 几乎不会写。 用于声明初始化方法和销毁方法 --> <bean id="us" class="com.itheima.service.impl.UserServiceImpl" scope="prototype" init-method="init" destroy-method="destory" ></bean>
2. 代码解释
//1. 创建好了工厂 classloader ---> 把class字节码加载到jvm里面去。 bin/classes ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //2. 问工厂要对象 UserService userService = (UserService) context.getBean("us");
userService.save();
//这行代码几乎不会写,因为它是关闭工厂。 ((AbstractApplicationContext) context).close();
五、Spring实例化方式
IOC的实例化方式。 这个对象的创建的方式
1. 无参构造方式【重点】
需要托管的类提供无参构造方法。
代码: public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("调用UserServiceImpl的save方法!~~~"); } } xml: <bean id="us" class="com.itheima.service.impl.UserServiceImpl"></bean>
2. 静态工厂方式【了解】
提供工厂类,里面放置一个静态方法,返回实例对象
代码:
public class StaticFactory {
public static UserService getBean(){ return new UserServiceImpl(); } }
xml:
<!-- 静态工厂的配置 --> <!-- <bean id="us" class="com.itheima.factory.StaticFactory" factory-method="getBean"></bean> -->
3. 实例工厂方式【了解】
提供工厂类,里面放置一个普通方法,返回实例对象
代码:
public class InstanceFactory {
public UserService getBean(){ return new UserServiceImpl(); } } xml: <!-- 实例工厂的配置 1. 我们拿着us问spring的工厂要实例。 2. spring拿着us找到匹配的bean. 3. 先根据factory-bean里面的factory 吧工厂给做出来。 4. 调用工厂里面的getBean方法返回实例。 5. spring的工厂拿到实例之后,再把实例返回给我们。 --> <bean id="factory" class="com.itheima.factory.InstanceFactory"></bean> <bean id="us" factory-bean="factory" factory-method="getBean"></bean>
不管是静态工厂还是实例工厂,都需要我们自己去维护实例的创建,这就增加了我们的编码量 。 等同于spring的工厂不做事情了,只是负责问我们做好的工厂要实例。
六、依赖注入
什么是依赖注入?
在创建某一个类的实例时, 对这个类中的属性 | 成员,进行赋值。
全称是 dependency Injection 翻译过来是依赖注入 本意是在实例化对象之前,对它里面的成员属性进行值的注入。
依赖注入的方式
其实就是平常我们给类里面的属性进行赋值的方式。
1.通过构造方法赋值
2.通过set方法赋值。
1. 使用构造方法注入
需要托管的类,提供有参构造方法
代码:
public class UserServiceImpl implements UserService { private String address; public UserServiceImpl(String address) { super(); this.address = address; } } xml: <bean id="us" class="com.itheima.service.impl.UserServiceImpl"> <constructor-arg name="address" value="深圳" ></constructor-arg> </bean>
2. 使用set方法注入
需要提供set方法
代码: public class UserServiceImpl implements UserService { private String address; public void setAddress(String address) { this.address = address; } } xml: <!--name 里面的值 和 setAddress 去掉set首字母小写 之后得到的 属性 一样 即 setAddress->address 如果是 setAddress1 --> address1 name="address1" --> <bean id="us" class="com.itheima.service.impl.UserServiceImpl"> <property name="address" value="北京"></property> </bean>
3. 注入的数据类型
普通类型数据
注入集合类型 、 数组、 map \ list
注入对象类型(我们自己定义的类)
3.1 注入集合类型数据
1. 数组类型
private String [] address;
public void setAddress(String [] address) { this.address = address; }
<!-- 注入数组 --> <property name="address"> <array> <value>地址1</value> <value>地址2</value> <value>地址3</value> <value>地址4</value> <value>地址5</value> </array> </property>
2. list类型
private List<String> address;
public void setAddress(List<String> address) { this.address = address; }
<!-- 注入list --> <property name="address"> <list> <value>地址11</value> <value>地址22</value> <value>地址33</value> <value>地址44</value> <value>地址55</value> </list> </property>
3. map类型
private Map<String , String> address;
public void setAddress(Map<String , String> address) { this.address = address; }
<!-- 注入map --> <property name="address"> <map> <entry key="aa" value="地址1"></entry> <entry key="bb" value="地址2"></entry> <entry key="cc" value="地址3"></entry> <entry key="dd" value="地址4"></entry> <entry key="ee" value="地址5"></entry> </map> </property>
3.2 注入对象类型【重点】
代码:
public class UserServiceImpl implements UserService { private UserDao userDao; //= new UserDaoImpl(); public void setUserDao(UserDao userDao) { this.userDao = userDao; } } xml: <!-- 1. 让spring帮忙创建UserDaoImpl的实例对象 --> <bean id="ud" class="com.itheima.dao.impl.UserDaoImpl"></bean> <!--name 里面的值 和 setUserDao 去掉set首字母小写 之后得到的 属性 一样 即 setUserDao->userDao 如果是 setUserDao1 --> userDao1 name="userDao1" --> <bean id="us" class="com.itheima.service.impl.UserServiceImpl"> <!-- 2. 把ud对应的那个类的实例给做出来,然后赋值给UserServiceImpl里面的userDao这个属性 --> <property name="userDao" ref="ud"></property> </bean>
4. 名称空间方式注入
这种手法仅仅是简化了我们在xml中的配置而已, 至于代码里面改用有参构造还是set方法,都必须要提供。
p名称空间
匹配的是set方法注入。 需要托管类提供set方法
<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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="us" class="com.itheima.service.impl.UserServiceImpl" p:address="深圳"> </bean> </beans>
c名称空间
匹配的是有参构造 , 需要托管类提供有参构造方法
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="us" class="com.itheima.service.impl.UserServiceImpl" c:address="深圳"> </bean> </beans>
SPEL 属性注入
可以完成逻辑运算
<bean id="us" class="com.itheima.service.impl.UserServiceImpl" > <property name="address" value="#{1>2}"/> </bean>
七、Spring整合Servlet
1. 初步整合
就是项目里面包含了servlet,也包含了spring即可。 获取类的实例方式和以前一样。
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService =(UserService) context.getBean("us");
userService.save();
引发的问题:
来一次访问,就必然创建一次工厂,这就很浪费了。
解决方案: 静态解决 , 工具类..
工厂创建时机有点晚了,等请求到来的时候才去创建工厂。
解决方案: 项目一发布,就马上创建工厂。
2. 进阶整合
监听ServletContext的创建, 因为只要项目一发布, 就会马上创建出来ServletContext的实例。连我们这种高智商的都能想得到, spring肯定也就想到了。spring其实已经写好了监听器。 我们只要注册这个监听器就够了,它会感知项目的发布,然后创建出来spring的工厂。
导入jar包 spring-web-xxx.jar
在web.xml 中配置 监听器 并且配置param 指定spring配置文件所在<!-- 这里仅仅是声明了一个监听器,只要servletContext创建了就执行监听器里面的方法。 在方法里面要解析xml文件,然后完成工厂的创建工作。 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
<!-- 指定了xml的位置在哪里 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
通过工具类获取之前创建好的工厂
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); //获取实例对象 UserService userService = (UserService) context.getBean("us"); userService.save();
八、总结
spring入门
IOC
实例化方式:
无参构造【重点】
静态工厂
实例工厂
DI
注入方式:
有参构造
set方法 【重点】
注入的数据类型
1. 普通数据
2. 集合数据
3. 对象数据【重点】
spring 整合servlet