1、主要的概念
1.1、介绍spring
它是一个分层的,轻量级的,一站式的 Java开发框架。为Java应用开发提供基础框架的支持。可以让开发者更专注与业务开发。最根本的使命是解决企业级应用开发的复杂性,即简化Java开发。
spring的官网:https://spring.io
1.2、spring的特点
1.2.1、轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。
1.2.2、控制反转(IOC)——Spring通过一种称作控制反转()的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。它的底层设计模式采用了工厂模式,所有的 Bean 都需要注册到Bean工厂中,将其初始化和生命周期的监控交由工厂实现管理。程序员只需要按照规定的格式进行Bean开发,然后利用XML文件进行bean 的定义和参数配置,其他的动态生成和监控就不需要调用者完成,而是统一交给了平台进行管理。 [4] 控制反转是软件设计大师 Martin Fowler在 2004 年发表的”Inversion of Control Containers and the Dependency Injection pattern”提出的。这篇文章系统阐述了控制反转的思想,提出了控制反转有依赖查找和依赖注入实现方式。控制反转意味着在系统开发过程中,设计的类将交由容器去控制,而不是在类的内部去控制,类与类之间的关系将交由容器处理,一个类在需要调用另一个类时,只要调用另一个类在容器中注册的名字就可以得到这个类的实例,与传统的编程方式有了很大的不同,“不用你找,我来提供给你”,这就是控制反转的含义 [5] 。
面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
2、IOC控制反转
2.1、问题引入
对于我们之前学习Java_Web的时候,遇到了一个问题:
对于Service业务层调用Dao数据层的方法的时候,我们需要new 数据层的对象,所以如果数据层的实现类发生变化,那么业务层的代码也需要跟着改变,发生变更后,都需要进行编译打包和重部署,这样子耦合度太高,不好!如何解决这个问题?
2.2、IOC的介绍
对于上面的问题,解决的方法就是使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象,这种实现思就是Spring的一个核心概念,此思想称为控制反转IOC。
-
Spring技术对IOC思想进行了实现
-
Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部"
-
IOC思想中的外部指的就是Spring的IOC容器
-
IOC容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象
-
被创建或被管理的对象在IOC容器中统称为Bean
-
IOC容器中放的就是一个个的Bean对象
2.3、Bean的基础配置
id、name、scope与class:
<bean id="xxx" name="xxx" class="xxx" scope="xxx"/>
id : bean的id,使用容器可以利用id找到对应的bean,在一个容器中id是唯一的。
class : bean的类型,即配置的bean的实现类路径 (必须写实现类,不能写到接口,因为接口是没办法创建对象的)
name: bean的别名,可定义多个别名,能用(,)(;)(空格)分开
scope:范围,可选范围为:singleton:单例(默认)和prototype(非单例)
IOC实例(仅调用Dao层作为案例)
package stukk.Dao;
public interface UserDao {
void deleteById(int id);
}
(Dao层的代码)
package stukk.Dao.Impl;
import stukk.Dao.UserDao;
public class UserDaoImpl implements UserDao {
public void deleteById(int id) {
System.out.println("第"+id+"个已被删除");
}
}
(实现类)
<?xml version="1.0" encoding="UTF-8"?>
<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-->
<bean id="userDao" class="stukk.Dao.Impl.UserDaoImpl"/>
</beans>
(配置文件)
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
public class App{
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao)context.getBean("userDao");
userDao.deleteById(2);
}
}
(最后在App类中从容器中获取对象进行方法调用,这个过程就不需要new来创造对象了!)
但是在代码中,我们需要把dao对象交给service,也就是说要绑定service和dao对象之间的关系,这又怎么做呢???接下来就是对象之间的关系绑定的方法
3、bean三种实例化方式
3.1、构造方法实例化:
bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成的。如下例:
package stukk.Dao.Impl;
import stukk.Dao.UserDao;
public class UserDaoImpl implements UserDao {
public UserDaoImpl(){
System.out.println("由构造方法创建");
}
public void deleteById(int id) {
System.out.println("第"+id+"个已被删除");
}
}
在实现类中的构造方法输出,结果运行成功,也会输出。说明内部走的依然是构造函数,能访问到类中的私有构造方法,显而易见Spring底层用的是反射。
3.2、静态工厂方式实例化
package stukk.Factory;
import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;
public class UserDaoFactory {
public static UserDao getUserDao(){
System.out.println("静态工厂方式创建");
return new UserDaoImpl();
}
}
(工厂类)
<bean id="userDao" class="stukk.Factory.UserDaoFactory" factory-method="getUserDao"></bean>
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;
public class App{
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao)context.getBean("userDao");
userDao.deleteById(100);
}
}
其中,class:工厂类的类全名,factory-mehod:具体工厂类中创建对象的方法名
3.3、实例工厂实例化
package stukk.Factory;
import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;
public class UserDaoFactory {
public UserDao getUserDao(){
System.out.println("实例工厂实例化bean");
return new UserDaoImpl();
}
}
创建工厂类的bean
<bean id="userFactory" class="stukk.Factory.UserDaoFactory"/>
<bean id="userDao" factory-bean="userFactory" factory-method="getUserDao"/>
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;
public class App{
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao)context.getBean("userDao");
userDao.deleteById(100);
}
}
配置的过程还是比较复杂,所以Spring为了简化这种配置方式就提供了一种叫FactoryBean
的方式来简化开发。将实现类继承FactoryBean即可
package stukk.Factory;
import org.springframework.beans.factory.FactoryBean;
import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;
public class UserFactoryBean implements FactoryBean {
public Object getObject() throws Exception {
System.out.println("实例化工厂实例化");
return new UserDaoImpl();
}
public Class<?> getObjectType() {
return UserDao.class;
}
}
<bean id="userDao" class="stukk.Factory.UserFactoryBean"/>
其他配置不变,运行即可得出。
范围默认是单例,那如果想改成单例具体如何实现?只需要将isSingleton()方法进行重写,修改返回为false,即可。
3.4、总结
Spring的IOC实例化对象的三种方式分别是:
-
构造方法(常用)
-
静态工厂(了解)
-
实例工厂(了解)
-
FactoryBean(实用)
-
4、bean的生命周期
-
首先理解下什么是生命周期?
-
从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期。
-
-
bean生命周期是什么?
-
bean对象从创建到销毁的整体过程。
-
-
bean生命周期控制是什么?
-
在bean创建后到销毁前做一些事情。
-
(1)关于Spring中对bean生命周期控制提供了两种方式:
-
在配置文件中的bean标签中添加
init-method
和destroy-method
属性 -
类实现
InitializingBean
与DisposableBean
接口,这种方式了解下即可。
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
package stukk.Dao.Impl;
import stukk.Dao.UserDao;
public class UserDaoImpl implements UserDao {
public void deleteById(int id) {
System.out.println("第"+id+"个已被删除");
}
public void init(){
System.out.println("init。。。");
}
public void destory(){
System.out.println("destroy......");
}
}
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;
public class App{
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao)context.getBean("userDao");
userDao.deleteById(100);
context.close();
}
}
(2)对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:
-
初始化容器
-
1.创建对象(内存分配)
-
2.执行构造方法
-
3.执行属性注入(set操作)
-
==4.执行bean初始化方法==
-
-
使用bean
-
1.执行业务操作
-
-
关闭/销毁容器
-
==1.执行bean销毁方法==
-
(3)关闭容器的两种方式:
-
ConfigurableApplicationContext是ApplicationContext的子类
-
close()方法
-
registerShutdownHook()方法
-
5、DI(Dependency Injection)依赖注入
我们知道Service层的方法依赖Dao层的对象来运行,在之前业务层要用数据层的类对象,以前是自己new
的,现在自己不new了,靠IOC容器来给注入进来,这种思想就是依赖注入(DI)
5.1、setter注入
案例:
1.删除业务层中使用new的方式创建的dao对象
2.在业务层提供UserDao的setter方法
3.在配置文件中添加依赖注入的配置
4.运行程序调用方法
package stukk.Service;
public interface UserService {
void deleteById(int id);
}
(UserService类)
package stukk.Service.Impl;
import stukk.Dao.BookDao;
import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;
import stukk.Service.UserService;
public class UserServiceImpl implements UserService {
UserDao userDao;
// = new UserDaoImpl(); 把他去掉了
public void deleteById(int id) {
userDao.deleteById(id);
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}//注意加入set方法哦!
}
(UserService实现类)
<?xml version="1.0" encoding="UTF-8"?>
<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-->
<bean id="userDao" class="stukk.Dao.Impl.UserDaoImpl"/>
<bean id="userService" class="stukk.Service.Impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
</beans>
(配置文件,为bean设置依赖注入 property标签表示配置当前bean的属性,name属性表示配置哪一个具体的属性,ref属性表示参照哪一个bean)
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;
public class App{
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)context.getBean("userService");
userService.deleteById(100);
}
}
(App类运行程序,结果OK)
5.2、注入简单数据类型
步骤:
1.在BookDaoImpl类中声明对应的简单数据类型的属性
2.为这些属性提供对应的setter方法
3.在applicationContext.xml中配置
package stukk.Dao.Impl;
import stukk.Dao.UserDao;
import java.math.BigInteger;
public class UserDaoImpl implements UserDao {
private String username;
private BigInteger password;
public void deleteById(int id) {
System.out.println("第"+id+"个已被删除");
System.out.println(username+":"+password);
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(BigInteger password) {
this.password = password;
}
}
<bean id="userDao" class="stukk.Dao.Impl.UserDaoImpl">
<property name="username" value="stu_kk"/>
<property name="password" value="123456789"/>
</bean>
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;
public class App{
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao)context.getBean("userDao");
userDao.deleteById(100);
}
}
5.3、构造器注入
在UserService实现类中利用构造方法进行注入
标签<constructor-arg>中
-
name属性对应的值为构造函数中方法形参的参数名,必须要保持一致。
-
ref属性指向的是spring的IOC容器中其他bean对象。
package stukk.Service.Impl;
import stukk.Dao.BookDao;
import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;
import stukk.Service.UserService;
public class UserServiceImpl implements UserService {
UserDao userDao;
public UserServiceImpl(UserDao userDao){
this.userDao = userDao;
}
public void deleteById(int id) {
userDao.deleteById(id);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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="userDao" class="stukk.Dao.Impl.UserDaoImpl">
<property name="username" value="stu_kk"/>
<property name="password" value="123456789"/>
</bean>
<bean id="userService" class="stukk.Service.Impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
</bean>
</beans>
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;
public class App{
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)context.getBean("userService");
userService.deleteById(10);
}
}
5.4、自动配置
前面的配置文件太麻烦了,所以有自动配置这种简便的方法
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
<bean id="userService" class="stukk.Service.Impl.UserServiceImpl" autowire="byType"/>
结果也是可以,和前面一样的结果
5.3、集合注入
常见的集合类型有哪些?
-
数组
-
List
-
Set
-
Map
-
Properties
针对不同的集合类型,进行注入!
package stukk.Dao.Impl;
import stukk.Dao.UserDao;
import java.math.BigInteger;
import java.util.*;
public class UserDaoImpl implements UserDao {
private int[] array;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
private Properties properties;
public void deleteById(int id) {
System.out.println("book dao save ...");
System.out.println("遍历数组:" + Arrays.toString(array));
System.out.println("遍历List" + list);
System.out.println("遍历Set" + set);
System.out.println("遍历Map" + map);
System.out.println("遍历Properties" + properties);
}
public void setArray(int[] array) {
this.array = array;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置bean-->
<bean id="userService" class="stukk.Service.Impl.UserServiceImpl" autowire="byType"/>
<bean id="userDao" class="stukk.Dao.Impl.UserDaoImpl">
<property name="array">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</array>
</property>
<property name="list">
<list>
<value>A</value>
<value>B</value>
<value>C</value>
<value>D</value>
</list>
</property>
<property name="set">
<set>
<value>a</value>
<value>b</value>
<value>c</value>
<value>d</value>
</set>
</property>
<property name="map">
<map>
<entry key="国家" value="中国"/>
<entry key="省份" value="广东省"/>
<entry key="市区" value="xx市"/>
</map>
</property>
<property name="properties">
<props>
<prop key="电子">烟假</prop>
<prop key="尼古">丁真</prop>
</props>
</property>
</bean>
</beans>
运行结果:
ok ,今天就到这,以后继续更新!坚持学习!!!