当前位置:金屋文档› Spring详解(学习总结)

Spring详解(学习总结)

文章标签:: spring 学习 java 后端
文章摘要: Spring是一个分层的java SE/EE full-stack(一站式)轻量级开源框架,以IOC(控制反转)和AOP(面向切面编程)为内核。在java三层架构当中分别提供了相应的技术:表现层(web层):SpringMVC框架业务层(service层):Bean管理(IOC容器)持久层(dao层):jdbcTemplate模板对象以及提供了ORM模块整合其他优秀的持久层技术。方便解耦,简化开发:Spring就是一个工厂,可以管理所有对象的创建和依赖关系维护,交给Spring管理。

目录

一、Spring概述

(一)、Spring是什么?

(二)、Spring框架发展历程

(三)、Spring框架的优势

(四)、Spring的体系结构

二、程序耦合与解耦合

(一)什么是程序的耦合

(二)解决程序耦合的思路

1、编译不依赖,运行时才依赖

2、使用工厂模式解耦合

三、SpringIOC机制的详解

(一)、IOC概述及作用

1、IOC的简介,设计思想

2、IOC作用

(二)SpringIOC入门案例前期准备

1、构建maven工程,添加Spring框架的依赖

2、创建持久层接口和实现类

3、创建业务层接口和实现类

4、在resources文件夹中创建一个任意名称的xml文件

5、让Spring管理资源,在配置文件中配置service和dao

6、测试IOC配置是否成功

(三)Spring基于XML的IOC细节

1、IOC配置文件详解:配置标签书写规范,配置标签的属性

2、SpringIOC机制源码解析

  (1) IOC容器解析

   (2)IOC容器底层bean初始化过程

(四)手动实现自己的IOC容器

1、分析IOC实现思路

2、IOC原理实现—环境搭建:构建maven工程,引入依赖

3、设计接口和类以及编写配置文件

4、使用xml技术解析配置文件

5、编写测试文件,展示测试结果

(五)Spring管理bean细节

1、bean实例化方式

(1)构造方法的方式

1)创建User类

2)配置Spring容器管理user类型对象

3)测试容器实例化User对象是否成功)

(2)静态工厂方式

1)创建静态工厂ItemFactory

2)配置Spring容器管理User类型对象

3)测试容器实例化User对象是否成功

(3)实例工厂方式

1)创建实例工厂NewItemFactory

2)配置Spring容器管理NewItemFactory类型对象

3)测试容器实例化User对象是否成功

2、bean作用域

(1)bean作用域介绍

(2)bean作用域的解析

1)当scope的取值为singleton时

2)当scope的取值为prototype时

3)当Scope的取值为其他值

四、Spring依赖注入(DI)

 (一)介绍

定义

(二)注入方式

1、构造函数注入

(1)构建Account类,提供所有属性的构造方法

(2)配置Account类(使用构造方法注入依赖数据)

(3)构造函数注入测试方法

2、setter注入

(1)修改Account类,添加属性的setter方法

(2)配置Account类(利用setter方法注入依赖数据)

(3)setter注入测试方法

3、注入集合数据

(1)修改Account类,添加集合属性

(2)配置Account类(利用setter注入依赖集合数据)

(3)集合注入测试方法

五、Spring配置文件模块化

(一)Spring模块化的介绍

(二)Spring模块化的配置

1、Spring模块化配置方式一

2、Spring模块化配置方式二

六、模块设计模式解析

(一)模块化设计模式介绍

(二)模板设计模式的应用场景

(三)模板设计模式实现

1、需求:用模块方法模式实现出国留学手续设计程序

2、代码实现

七、Spring整合JDBC实现用户的CRUD

(一)整合思路分析

(二)构建maven工程,添加技术依赖

(三)构建数据库表并编写实体类Account

(四)编写持久层代码AccountDao以及实现类AccountDaoImpl

(五)编写业务层代码Accountservice以及实现类AccountServiceImpl

(六)创建并编写配置文件:配置容器管理对象

(七)测试代码

 八、常用注解

(一)创建对象的注解

(二)用于注入数据的注解

(三)用于改变作用范围的注解

九、基于注解的IOC案例

(一)构建工程,添加依赖

(二)使用注解配置

(三)创建配置文件并开启对注解的支持

(四)编写测试代码

十、纯注解配置

(一)新注解说明

(二)通过注解获取容器

十一、Spring整合Junit

(一)IOC测试类中的问题和解决思路

(二)整合Junit配置步骤

1、添加技术依赖

2、使用@RunWith注解替换原有运行器

3、使用@ContextConfiguration 指定 Spring 配置文件的位置

4、使用@Autowired 给测试类中的变量注入数据

十二、Spring整合DButils实现转账业务

(一)添加转账方法,并演示事务问题

1、转账Account表以及对应的实体bean

2、引入DBUtils依赖坐标

3、创建Account接口和对应实现类

4、创建AccountService接口和实现类

5、测试转账业务

(二)编写ConnectionUtils工具类管理数据库连接

(三)编写事务管理工具类

(四)编写业务层和持久层控制代码并配置Spring的IOC

(五)测试转账

(六)转账业务案例中存在的问题

(七)使用动态代理实现事务控制

1、创建代理工具类

2、配置并测试动态代理转账业务

十三、SpringAOP机制详解

 (一)AOP概述

1、什么是AOP

2、AOP编程思想

3、Spring中的常用术语

4、AOP编程底层的实现机制

(1)JDK动态代理

(2)CGLB动态代理

5、AOP的作用及优势

(二)Spring基于XML的AOP配置

1、环境搭建

(1)添加依赖 

(2)添加代码

(3)创建配置文件并导入约束

(4)配置Spring的IOC

(5)抽取公共代码制作成通知

2、AOP配置步骤

(1)配置bean标签

(2)使用aop:config 声明AOP配置

(3)使用aop:aspect 配置切面

(4)使用aop:pointcut配置切入点表达式

(5)使用aop:xxx配置对应的通知类型

3、切入点表达式说明

4、环绕通知配置事务管理

(三)Spring基于注解的AOP配置

1、环境搭建

(1)构建maven工程添加AOP注解的相关依赖

(2)导入代码

(3)在配置文件中导入context的名称空间且配置

(4)资源使用注解配置

(5)在配置文件中指定spring要扫描的包

2、配置步骤

(1)通知类使用注解配置

(2)通知类使用@Aspect注解声明为切面

(3)增强方法上使用注解配置通知

(4)开启Spring对注解AOP的支持

(5)环绕通知注解配置

(6)切入点表达式注解

十四、Spring事务详解

(一)Spring基于XML的事务配置

1、环境搭建

(1)构建工程,添加依赖

(2)创建Spring的配置文件,导入约束

(3)沿用转账业务

2、事务管理配置步骤

(1)配置事务管理器

(2)配置事务的通知引用事务管理器

(3)配置事务的属性

(4)配置AOP切入点表达式

(5)配置切入点表达式和事务通知的对应关系

(二)Spring基于注解的事务配置

1、环境搭建

(1)构建maven工程,添加相关依赖

(2)创建Spring配置文件

(3)沿用转账业务的代码:dao实现类和service实现类采用注解的形式,添加到容器中管理

2、事务管理配置步骤

(1)配置事务管理器并注入数据源

(2)在业务层使用@Transactional注解

(3)配置文件中开启Spring对注解事务的支持

十五、Spring整合Mybatis实现用户的CRUD

(一)整理思路分析

(二)构建maven工程,添加依赖

(三)构建数据库表并创建实体类

(四)编写dao层的接口UserMapper

(五)构建mapper接口对应的sql配置文件

(六)构建服务层接口UserService

(七)构建服务层实现类UserServiceImpl

(八)构建配置文件

(九)测试代码


一、Spring概述

(一)、Spring是什么?

Spring是一个分层的java SE/EE full-stack(一站式)轻量级开源框架,以IOC(控制反转)和AOP(面向切面编程)为内核。

在java三层架构当中分别提供了相应的技术:

表现层(web层):SpringMVC框架

业务层(service层):Bean管理(IOC容器)

持久层(dao层):jdbcTemplate模板对象以及提供了ORM模块整合其他优秀的持久层技术。

(二)、Spring框架发展历程

1997年,IBM提出了EJB的思想。1998年,SUN制定开发标准规范EJB1.0.。199年EJB1.1发布。2001年,EJB2.0发布。2006年EJB3.0发布。

Rod Johnson ( Spring 之父) Expert One-to-One J2EE Design and Development(2002) 阐述了 J2EE
使用EJB 开发设计的优点及解决方案 Expert One-to-One J2EE Development without EJB(2004) 阐述了 J2EE 开发不使用 EJB的解决方式(Spring 雏形)
2017 年 9 月份发布了 Spring 的最新版本 Spring5.0 通用版(GA)

(三)、Spring框架的优势

方便解耦,简化开发:Spring就是一个工厂,可以管理所有对象的创建和依赖关系维护,交给Spring管理。

AOP编程的支持:可以方便的实现对程序进行权限拦截,日志记录,运行的监控。

声明式事务的支持:通过配置的方式完成对事务的管理,无需手动编程。

方便程序的测试:对Junit支持,可以通过注解方式方便的对Spring程序进行测试。

整合外部优秀技术:Spring内部提供了对各种优秀框架(Hibernate,Mybatis)的直接支持。

javaEE技术的封装;Spring对javaEE开发当中复杂难用的API进行封装,降低了这些API的使用难度。

(四)、Spring的体系结构

二、程序耦合与解耦合

(一)什么是程序的耦合

程序的耦合是程序之间的关联性,也就是多个类的联系是否紧密,多个对象之间的关系是否密切。

生活中的案例:
你的房子里面有窗子,那么房子和窗子就有了关联
耦合度是松还是紧就看你的关联是强还是弱,也就是修改的代价,比如你窗子是扣死在墙里的那么你修改窗子就必须修改墙 这就比较紧密了,反应在程序上就是耦合度高,不利于程序的扩展和维护。
但是如果你窗子是按照某种规格的 可以自由拆装的,那么修改的代价就小,耦合度也就低了,反应在程 序上就是耦合度低,利于程序的扩展和维护。
我们写程序的目标就是 高内聚 低耦合!

(二)解决程序耦合的思路

1、编译不依赖,运行时才依赖

当我们讲解jdbc时,是通过反射来注册驱动的,代码如下:

Class.forName("com.mysql.jdbc.Driver");//使用的驱动类是指定了一个字符串

我们的类中在编译阶段不再需要具体的驱动类,就算删除mysql的驱动jar包,依然可以通过编译。在运行阶段才会依赖驱动包。实际开发当中,我们应该做到编译不依赖,运行时才依赖。

上述代码产生的新问题,mysql驱动类的全限定类名作为一个字符串java类中是写死的,一旦发生改变,还需要修改源码。

使用配置文件结合反射就可以解决上述问题。

2、使用工厂模式解耦合

在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。

那么这个读取配置文件,创建和获取三层对象的类就是工厂。

三、SpringIOC机制的详解

(一)、IOC概述及作用

1、IOC的简介,设计思想

SpringIOC:IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。

IOC这个概念简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部透明的,从而降低了解决问题的复杂度,而且可以灵活的被重用和扩展。

IOC理论提出的观点大体是这样的:借助于第三方实现具有依赖关系的对象之间的解耦。

                

 由于引进了中间位置“第三方”,也就是IOC容器,使得A、B、C、D这四个对象没有了耦合关系,齿轮之间的传动全部依靠IOC容器,全部对象的控制权上交给IOC容器,所以IOC容器成了整个系统的关键核心,它起到一个“粘合剂”的作用,把系统中所有对象粘合在一起发挥作用。

                        

当把图中的IOC容器拿掉,可以发现A、B、C、D这四个 对象之间没有耦合关系。这样的话,当我们去实现A的时候,根本无需去考虑其他几个对象,对象之间的依赖关系已经讲到了最低程度。

2、IOC作用

IOc本质上就是一个大工程,大容器。主要作用就是创建和管理对象的依赖关系,削减计算机程序的耦合(解除我们代码间的依赖关系),提高程序的可扩展性和可维护性。

(二)SpringIOC入门案例前期准备

1、构建maven工程,添加Spring框架的依赖

<properties> <spring.version>5.2.5.RELEASE</spring.version></properties><!--导入spring的context坐标,context依赖core、beans、expression aop--><dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency></dependencies>

2、创建持久层接口和实现类

public interface UserDao { public void save();}public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("userDao save method running...... "); }}

3、创建业务层接口和实现类

public interface UserService { public void saveService();}public class UserServiceImpl implements UserService { @Override public void saveService() { System.out.println("userSerivce save method running......"); }}

4、在resources文件夹中创建一个任意名称的xml文件

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/springbeans.xsd"></beans>

5、让Spring管理资源,在配置文件中配置service和dao

<?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"> <!--配置userDaoImpl--> <bean id="userDao" class="com.ujiuye.dao.impl.UserDaoImpl"></bean> <!--配置userServiceImpl--> <bean id="userService" class="com.ujiuye.service.UserServiceImpl"></bean></beans>

6、测试IOC配置是否成功

@Testpublic void test1(){ //1:获得spring IOC容器对象: ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //2:从容器当中根据id获得UserDaoImpl 对象,执行userDao对象的save方法 UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.save(); //3:从容器当中根据id获得UserServiceImpl 对象,执行userService对象的saveService方法 UserService userService = (UserService)applicationContext.getBean("userService"); userService.saveService();}

运行结果:

 

(三)Spring基于XML的IOC细节

1、IOC配置文件详解:配置标签书写规范,配置标签的属性

bean标签:用于配置对象交给Spring来创建

        默认情况下他会调用类中无参数的构造器,如果没有无参数构造器则不能创建成功。

基本属性:

        id:Bean实例对象在Spring容器中的唯一标识

        class:Bean的全限定类名

2、SpringIOC机制源码解析

  (1) IOC容器解析

IOC思想基于IOC容器完成,IOC容器底层就是对象工厂,Spring中工厂的类结构图如下;

                

         1)BeanFactory:IOC容器的基本实现,是Spring内部使用的接口,不提供开发人员使用,加载配置文件时,不会创建对象,在获得(使用)对象时才采取创建对象。

        2)HierarchicalBeanFactory:这个工厂接口非常简单,实现了Bean工厂的分层。工厂接口也是继承自BeanFactory,也是一个二级接口,相对于父接口,他只是扩展了一个重要的功能———工厂分层

        3)AutowireCapableBeanFactory:该接口有自动配置能力,需要注意的是,ApplicationContext接口并实现此接口,因为应用代码很少用到此功能,如果确实需要的话,可以调用ApplicationContext的getAutowireCapableBeanFactory方法,来获取此接口的实例

        4)ListableBeanFactory:获取bean时,Spring鼓励使用这个接口定义的api,如查看bean

的个数、获取某一类型Bean的配置名、查看容器中是否包括某一Bean等方法。

        5)ApplicationContext:BeanFactory接口的子接口,提供更多强大的功能,一般由开发人员使用。接口提供了bean基础性操作同时,扩展了国际化等功能。ApplicationContext接口在加载配置文件时候就会配置文件当中的对象进行创建,存放IOC容器当中

        6)AnnotationConfigApplicationContext:当使用注解配置容器对象时,需要使用此类来创建spring容器。他用来读取注解。

        7)ClassPathXmlApplicationContext:它是从类的根路径下加载配置文件

        8)FileSystemXmlApplicationContext:它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

   (2)IOC容器底层bean初始化过程

        1)BeanFactionPostProcessor

        作用:定义了在bean工厂对象创建后,bean对象创建前执行的动作,用于对工厂进行创建后业务处理

        运行时机:操作用于对工厂进行处理,仅运行一次

        2) BeanPostProcessor

作用:定义了所有bean初始化前后进行的统一动作,用于对bean进行创建前业务处理与创建后业务处理

        运行时机:当前操作伴随着每个bean的创建过程,每次创建bean均运行该操作。

        3)InitializingBean

        作用:定义了每个bean的初始化前进行的动作,属于非统一性动作,用于对bean进行创建前业务处理。

        运行时机:当前操作伴随着任意一个bean的创建过程,保障其个性化业务处理

(四)手动实现自己的IOC容器

1、分析IOC实现思路

        

2、IOC原理实现—环境搭建:构建maven工程,引入依赖

<properties> <spring.version>5.2.5.RELEASE</spring.version> </properties> <dependencies> <!--导入spring的context坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!--导入junit单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>

3、设计接口和类以及编写配置文件

//设定UserDao接口public interface UserDao { public void save();}//设定UserDao接口实现类public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("userDao save method running...... "); }}

配置文件:

<!--配置userDaoImpl--><bean id="userDao" class="com.ujiuye.dao.impl.UserDaoImpl"></bean>

4、使用xml技术解析配置文件

<!--引入dom4J--><dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version></dependency>
/*** 创建自己的工厂类*/public class MyBeanFactory { //创建一个map集合,模拟IOC容器 private static Map<String,Object> map = new HashMap<>(); static{ try { //使用dom4J 解析xml文件: //第一步:获得一个解析器: SAXReader reader = new SAXReader(); //第二: 读取外部的配置文件: String path = "src/main/resources/applicationContext.xml"; //第三: 读取了整个文档对象 Document document = reader.read(path); //第四: 获得根节点: Element rootElement = document.getRootElement();//beans //第五: 获得根节点下的所有的bean 标签对应的节点: List<Element> bean = rootElement.elements("bean");// bean for (Element element : bean) { //获得id属性对应的值: String id1 = element.attributeValue("id"); //获得class属性对应的值:【全限定类名】 String aClass = element.attributeValue("class");//获得class对应的值: 全限定类名。 //通过反射创建对象: Class clz = Class.forName(aClass); Object object = clz.newInstance(); //存容器 id做key,创建出来的对象value map.put(id1,object); } } catch (Exception e) { e.printStackTrace(); }}
/*** 根据id从容器当中获得对象* @param id id的名称* @return 返回Object类型对象*/public static Object getBean(String id){ Object o = map.get(id); return o; }}

5、编写测试文件,展示测试结果

@Testpublic void testMyFactory(){ //1:创建工厂对象 MyBeanFactory factory =new MyBeanFactory(); //2:从容器当中根据id获得对象 UserDao userDao = (UserDao) factory.getBean("userDao"); System.out.println(userDao); userDao.save();}

(五)Spring管理bean细节

1、bean实例化方式

(1)构造方法的方式

1)创建User类
public class User implements Serializable {    public User(){        System.out.println("user created...");   }}

2)配置Spring容器管理user类型对象
<!--配置user对象--><bean id="user" class="com.ujiuye.pojo.User"></bean>

3)测试容器实例化User对象是否成功)
@Testpublic void testUser(){    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");    User user = (User) context.getBean("user");    System.out.println(user);}

(2)静态工厂方式

1)创建静态工厂ItemFactory
public class ItemFactory {    //静态方法返回实例bean    public static User createUser(){        System.out.println("static method running create bean ......");        return new User();   }}

2)配置Spring容器管理User类型对象
<!--静态工厂实例化对象--><bean id="user" class="com.ujiuye.factory.ItemFactory"></bean>

3)测试容器实例化User对象是否成功
@Testpublic void testItemFactory(){    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");    User user = (User) context.getBean("user");    System.out.println(user);}

(3)实例工厂方式

1)创建实例工厂NewItemFactory
public class NewItemFactory {    //工厂的非静态方法返回bean实例    public User createUser(){        System.out.println("Dynamic method running create bean ......");        return new User();   }}

2)配置Spring容器管理NewItemFactory类型对象
​<!--实例工厂--><bean id="itemFactory" class="com.ujiuye.factory.NewItemFactory"></bean><bean id="user" factory-bean="itemFactory" factory-method="createUser"></bean>​
3)测试容器实例化User对象是否成功
@Testpublic void testNewItemFactory(){    ApplicationContext context =    new ClassPathXmlApplicationContext("applicationContext.xml");    User user = (User) context.getBean("user");    System.out.println(user);}

2、bean作用域

(1)bean作用域介绍

所谓Bean的作用域其实就是指Spring给我们创建出的对象的存活范围,在配置文件中通过bean的scope属性指定

scope:指对象的作用范围,取值如下:

取值范围说明
singleton默认值,单例的
prototype多例的
requestWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
sessionWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
global sessionWEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session

(2)bean作用域的解析

1)scope的取值为singleton时

Bean的实例化个数:1个

Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例

2)scope的取值为prototype时

Bean的实例化个数:多个

Bean的实例化时机:当调用getBean()方法时实例化Bean

3)Scope的取值为其他值

scope指定为其他值,需要在特定的环境下使用。

四、Spring依赖注入(DI)

 (一)介绍

定义

它是SpringBoot框架核心IOC的具体实现。组件之间的依赖关系由容器在应用系统运行期来决定,也就是由动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。

(二)注入方式

1、构造函数注入

(1)构建Account类,提供所有属性的构造方法

顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 Spring 框架来为我们注入。具体代码如下:
public class Account {private String name;private Integer age;private Date birthday;public Account(String name, Integer age, Date birthday) { this.name = name; this.age = age; this.birthday = birthday; }}

(2)配置Account类(使用构造方法注入依赖数据)

<!--使用构造函数的方式:给account中的属性赋值要求:类中需要提供一个对应参数列表的构造器函数涉及的标签:constructor-arg:属性:name: 执行参数在构造器中的名称value:它能赋的值是基本数据类型和 String 类型ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean--><bean id="now" class="java.util.Date"></bean><bean id="account" class="com.ujiuye.pojo.Account"> <constructor-arg name="name" value="王达"></constructor-arg> <constructor-arg name="age" value="20"></constructor-arg> <constructor-arg name="birthday" ref="now"></constructor-arg></bean>

(3)构造函数注入测试方法

@Testpublic void testDI(){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Account account = (Account) applicationContext.getBean("account"); System.out.println("name:"+account.getName()+" age:"+account.getAge()+"birthday:"+account.getBirthday()); //打印结果: name:王达 age:20 birthday:Thu Feb 04 13:53:45 CST 2021}

2、setter注入

(1)修改Account类,添加属性的setter方法

public class Account { private String name; private Integer age; private Date birthday; public Account() { } public Account(String name, Integer age, Date birthday) { this.name = name; this.age = age; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; }}

(2)配置Account类(利用setter方法注入依赖数据)

<!--使用set方法的方式给属性赋值涉及的标签: property属性:name:找的是类中set方法后面的部分ref: 给属性赋值是其他bean类型的value:给属性赋值是基本数据类型和 string 类型的实际开发当中, 此种方式用的比较多,推荐使用--><bean id="now" class="java.util.Date"></bean><bean id="account" class="com.ujiuye.pojo.Account"> <property name="name" value="张三丰"></property> <property name="age" value="31"></property> <property name="birthday" ref="now"></property></bean>

(3)setter注入测试方法

@Testpublic void testDI(){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Account account = (Account) applicationContext.getBean("account"); System.out.println("name:"+account.getName()+" age:"+account.getAge()+"birthday:"+account.getBirthday()); //测试结果: name:张三丰 age:31 birthday:Thu Feb 04 14:05:19 CST 2021}

3、注入集合数据

(1)修改Account类,添加集合属性

给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。
我们这里介绍注入数组,List,Set,Map,Properties。具体代码如下:
public class Account { //注入数组,List集合,Set集合,Map集合,Properties集合属性 private String[] myStrs; private List<String> myList; private Set<String> mySet; private Map<String,String> myMap; private Properties myProps; public Account() { } public String[] getMyStrs() { return myStrs; } public void setMyStrs(String[] myStrs) { this.myStrs = myStrs; } public List<String> getMyList() { return myList; } public void setMyList(List<String> myList) { this.myList = myList; } public Set<String> getMySet() { return mySet; } public void setMySet(Set<String> mySet) { this.mySet = mySet; } public Map<String, String> getMyMap() { return myMap; } public void setMyMap(Map<String, String> myMap) { this.myMap = myMap; } public Properties getMyProps() { return myProps; } public void setMyProps(Properties myProps) { this.myProps = myProps; }}

(2)配置Account类(利用setter注入依赖集合数据)

<!--注入集合类型数据: 涉及到标签: List结构: array list set Map结构: map entry props prop--><bean id="account" class="com.ujiuye.pojo.Account"><!--注意:在注入集合数据时,只要是结构相同,标签可以互换--> <!--注入数组数据--> <property name="myStrs"> <array> <value>array-AAA</value> <value>array-BBB</value> <value>array-CCC</value> </array> </property> <!--注入List集合数据--> <property name="myList"> <list> <value>list-AAA</value> <value>list-BBB</value> <value>list-CCC</value> </list> </property> <!--注入Set集合数据--> <property name="mySet"> <list> <value>set-AAA</value> <value>set-BBB</value> <value>set-CCC</value> </list> </property> <!--注入Map集合--> <property name="myMap"> <map> <entry key="map-a" value="AAA"></entry> <entry key="map-b"> <value>BBB</value> </entry> </map> </property> <!--注入Properties集合--> <property name="myProps"> <props> <prop key="pro-a">AAA</prop> <prop key="pro-b">BBB</prop> </props> </property></bean>

(3)集合注入测试方法

@Testpublic void testDI(){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Account account = (Account) applicationContext.getBean("account"); System.out.println("array:"+ Arrays.toString(account.getMyStrs())); System.out.println("list:"+account.getMyList()); System.out.println("set:"+account.getMySet()); System.out.println("map:"+account.getMyMap()); System.out.println("props:"+account.getMyProps());/*测试结果:array:[array-AAA, array-BBB, array-CCC]list:[list-AAA, list-BBB, list-CCC]set:[set-AAA, set-BBB, set-CCC]map:{map-a=AAA, map-b=BBB}props:{pro-b=BBB, pro-a=AAA}*/}

五、Spring配置文件模块化

(一)Spring模块化的介绍

        我们现在的配置都集中配在了一个applicationContext.xml文件中,当开发人员过多时, 如果所有bean 都配置到同一个配置文件中,会使这个文件巨大,而且也不方便维护。 针对这个问题,Spring提供了多配置文件的方式,也就是所谓的配置文件模块化。

(二)Spring模块化的配置

1、Spring模块化配置方式一

并列的多个配置文件直接编写多个配置文件,比如beans1.xml,beans2.xml,...,然后在创建ApplicationContext的时候,直接传入多个配置文件。

ApplicationContext act = new ClassPathXmlApplicationContext("beans1.xml","beans2.xml","...");

2、Spring模块化配置方式二

主从配置文件,先配置一个主配置文件,然后在里面导入其他的配置文件。

<import resource="beans1.xml" /><import resource="beans2.xml" />

注意:

    同一个xml文件中不能出现相同名称的bean,如果出现会报错。‘’

        多个xml文件如果出现相同的名称的bean,不会报错,但是后加载的会覆盖前加载的bean,所以企业开发中尽量保证bean的名称是唯一的。

六、模块设计模式解析

(一)模块化设计模式介绍

模块方法(Template Method)模式的定义:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。

模块方法模式的静态结构图:

                                                

(二)模板设计模式的应用场景

在多个子类中拥有相同的方法,而且逻辑相同时,可以将这些方法抽出来发到一个模块抽象类中程序主框架相同,细节不同的情况下,也可以使用模块方法。

举例说明:

  • 使用过Servlet的人都清楚,除了要在web.xml做相应的配置外,还需继承一个叫HttpServlet的抽象类。HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体子类提供,因此这是典型的模板方法模式。
  • 持久层对数据库的操作,Spring提供了JdbcTemplate模板对象, 完成CRUD操作。

(三)模板设计模式实现

1、需求:用模块方法模式实现出国留学手续设计程序

分析:出国留学手续一般经过以下流程:索取学校资料,提出入学申请,办理因私出国护照、出境卡和公证,申请签证,体检、订机票、准备行装,抵达目标学校等,其中有些业务对各个学校是一样的,但有些业务因学校不同而不同,所以比较适合用模板方法模式来实现。

在本实例中,我们先定义一个出国留学的抽象类 StudyAbroad,里面包含了一个模板方法 TemplateMethod(),该方法中包含了办理出国留学手续流程中的各个基本方法,其中有些方法的处理由于各国都一样,所以在抽象类中就可以实现,但有些方法的处理各国是不同的,必须在其具体子类(如美国留学类 StudyInAmerica)中实现。如果再增加一个国家,只要增加一个子类就可以了。

                

2、代码实现

抽象类:

//抽象类: 出国留学public abstract class StudyAbroad { //定义抽象方法,索取学校资料 public abstract void LookingForSchool(); //定义抽象方法,定义入学申请 public abstract void ApplyForEnrol(); //定义入学申请方法: public void ApplyForPassport() { System.out.println("三.办理因私出国护照、出境卡和公证:"); System.out.println(" 1)持录取通知书、本人户口簿或身份证向户口所在地公安机关申请办理因私出国护照和出境卡。"); System.out.println(" 2)办理出生公证书,学历、学位和成绩公证,经历证书,亲属关系公证,经济担保公证。"); } //定义申请签证方法 public void ApplyForVisa() { System.out.println("四.申请签证:"); System.out.println(" 1)准备申请国外境签证所需的各种资料,包括个人学历、成绩单、工作经历的证明;个人及家庭收入、资金和财产证明;家庭成员的关系证明等;"); System.out.println(" 2)向拟留学国家驻华使(领)馆申请入境签证。申请时需按要求填写有关表格,递交必需的证明材料,缴纳签证。有的国家(比如美国、英国、加拿大等)在申请签证时会要求申请人前往使(领)馆进行面试。"); } //体检、订机票、准备行装 方法 public void ReadyGoAbroad() { System.out.println("五.体检、订机票、准备行装:"); System.out.println(" 1)进行身体检查、免疫检查和接种传染病疫苗;"); System.out.println(" 2)确定机票时间、航班和转机地点。"); } //定义抵达抽象方法 public abstract void Arriving(); }

子类

//定义具体的子类,美国留学public class StudyInAmerica extends StudyAbroad { //索取资料的具体实现 @Override public void LookingForSchool() { System.out.println("一.索取学校以下资料:"); System.out.println(" 1)对留学意向国家的政治、经济、文化背景和教育体制、学术水平进行较为全面的了解;"); System.out.println(" 2)全面了解和掌握国外学校的情况,包括历史、学费、学制、专业、师资配备、教学设施、学术地位、学生人数等;"); System.out.println(" 3)了解该学校的住宿、交通、医疗保险情况如何;"); System.out.println(" 4)该学校在中国是否有授权代理招生的留学中介公司?"); System.out.println(" 5)掌握留学签证情况;"); System.out.println(" 6)该国政府是否允许留学生合法打工?"); System.out.println(" 8)毕业之后可否移民?"); System.out.println(" 9)文凭是否受到我国认可?"); } //入学申请的具体实现 @Override public void ApplyForEnrol() { System.out.println("二.入学申请:"); System.out.println(" 1)填写报名表;"); System.out.println(" 2)将报名表、个人学历证明、最近的学习成绩单、推荐信、个人简历、托福或雅思语言考试成绩单等资料寄往所申请的学校;"); System.out.println(" 3)为了给签证办理留有充裕的时间,建议越早申请越好,一般提前1年就比较从容。"); } //抵达的具体实现 @Override public void Arriving() { System.out.println("六.抵达目标学校:"); System.out.println(" 1)安排住宿;"); System.out.println(" 2)了解校园及周边环境。"); }}
public class StudyAbroadProcess { public static void main(String[] args) { StudyAbroad tm = new StudyInAmerica(); tm.TemplateMethod(); }}

七、Spring整合JDBC实现用户的CRUD

(一)整合思路分析

Spring提供了ioc容器,管理jdbc操作数据库的过程中需要的数据库连接对象,同时Spring提供了整合jdbc操作数据库的工具类JdbcDaoSupport 和模板工具 JdbcTemplate,在JdbcTemplate中提供了大量的操作数据库的方式供用户使用。所以我们只需要获取模板工具类然后调用方法就可以完成Jdbc的操作了。

(二)构建maven工程,添加技术依赖

<dependencies> <!--导入spring的context坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!--导入Jdbc模块依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!--导入Mysql 驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--导入C3P0连接池--> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!--导入junit单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency></dependencies>

(三)构建数据库表并编写实体类Account

public class Account implements Serializable { private Integer id; private String name; private double money; 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 double getMoney() { return money; } public void setMoney(double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; }}

(四)编写持久层代码AccountDao以及实现类AccountDaoImpl

public interface AccountDao { public void save(Account account); public void delete(Integer id); public void update(Account account); public Account findById(Integer id); public Integer getTotalRecords(); public List<Account> findAll();}
public class AccountDaoImpl implements AccountDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public void save(Account account) { String sql ="insert into account(name,money) values(?,?)"; jdbcTemplate.update(sql,account.getName(),account.getMoney()); } @Override public void delete(Integer id) { String sql ="delete from account where id = ? "; jdbcTemplate.update(sql,id); } @Override public void update(Account account) { String sql ="update account set money = ? , name=? where id= ?"; jdbcTemplate.update(sql,account.getMoney(),account.getName(),account.getId()); } @Override public Account findById(Integer id) { String sql ="select * from account where id = ? "; Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Account>(Account.class),id); return account; } @Override public Long getTotalRecords() { Long count = jdbcTemplate.queryForObject("select count(*) from account",Long.class); System.out.println(count); return count; } @Override public List<Account> findAll() { String sql ="select * from account"; List<Account> accountList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Account>(Account.class)); return accountList; }}

(五)编写业务层代码Accountservice以及实现类AccountServiceImpl

public interface AccountService { public void save(Account account); public void delete(Integer id); public void update(Account account); public Account findById(Integer id); public Long getTotalRecords(); public List<Account> findAll();}
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void save(Account account) { accountDao.save(account); } @Override public void delete(Integer id) { accountDao.delete(id); } @Override public void update(Account account) { accountDao.update(account); } @Override public Account findById(Integer id) { return accountDao.findById(id); } @Override public Long getTotalRecords() { return accountDao.getTotalRecords(); } @Override public List<Account> findAll() { return accountDao.findAll(); }}

(六)创建并编写配置文件:配置容器管理对象

将数据库的连接信息抽取到外部配置文件中,和spring的配置文件分离开,有利于后期维护

jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/testjdbc.username=rootjdbc.password=root
<!--数据源对象--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/></bean><!--配置JdbcTemplate模板对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/></bean><!--配置AccountDaoImpl对象--><bean id="accountDao" class="com.ujiuye.dao.impl.AccountDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property></bean><!--配置AccountServiceImpl对象--><bean id="accountService" class="com.ujiuye.service.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property></bean>

(七)测试代码

//测试save方法@Testpublic void testJdbcTemplateSave(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService service = (AccountService) context.getBean("accountService"); Account account = new Account(); account.setName("jack"); account.setMoney(1001D); service.save(account);}//测试update方法@Testpublic void testJdbcTemplateUpdate(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService service = (AccountService) context.getBean("accountService"); Account account = new Account(); account.setName("jack2"); account.setMoney(999D); account.setId(1008); service.update(account);}//测试delete方法@Testpublic void testJdbcTemplateDelete(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService service = (AccountService) context.getBean("accountService"); service.delete(1001);}//测试唯一性查询findById@Testpublic void testJdbcTemplateFindById(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService service = (AccountService) context.getBean("accountService"); Account account = service.findById(1001); System.out.println(account);}//测试总记录数@Testpublic void testJdbcTemplateGetTotalRecords(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService service = (AccountService) context.getBean("accountService"); Long totalRecords = service.getTotalRecords(); System.out.println("表当中的总记录数为:"+totalRecords);}//测试账户列表@Testpublic void testJdbcTemplateGetAll(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService service = (AccountService) context.getBean("accountService"); List<Account> accountList = service.findAll(); accountList.forEach((account -> { System.out.println(account); }));}

 八、常用注解

(一)创建对象的注解

注解说明
@Component使用在类上用于实例化Bean
@Controller使用在web层类上用于实例化Bean
@Service使用在service层类上用于实例化Bean
@Repository使用在dao层类上用于实例化Bean

注意:

  • 使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描一便识别使用注解配置的类、字段和方法。
<!--注解的组件扫描--><context:component-scan base-package="com.ujiuye"></context:component-scan>
  • 使用@Component或@Repository标识UserDaoImpl需要Spring进行实例化。
//@Component("userDao")@Repository("userDao")public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("save running... ..."); }}
  • 使用@Component或Service标识UserServiceImpl需要Spring进行实例化
//@Component("userService")@Service("userService")public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("save running... ..."); }}

(二)用于注入数据的注解

注解说明
@Value注入普通属性
@Autowired

自动按照类型注入。当使用注解注入属性时,set 方法可以省略。它只能注入其他 bean 类型。当有多个类型匹配时,使用要注入的对象变量名称作为 bean 的id,在 spring 容器查找,找到了也可以注入成功。找不到就报错。

@Qualifier

结合@Autowired一起使用用于根据名称进行依赖注入

@Resource

相当于@Autowired+@Qualifier,按照名称进行注入

  • 使用@Value进行字符串的注入
@Repository("userDao")public class UserDaoImpl implements UserDao { @Value("注入普通数据") private String str; @Value("${jdbc.driver}") private String driver; @Override public void save() { System.out.println(str); System.out.println(driver); System.out.println("save running... ..."); }}
  • 使用Autowired或者@Autowired+@Qulifier或者@Resource进行userDao的注入
//@Component("userService")@Service("userService")public class UserServiceImpl implements UserService { /*@Autowired @Qualifier("userDao")*/ @Resource(name="userDao") private UserDao userDao; @Override public void save() { userDao.save(); }}

(三)用于改变作用范围的注解

注解说明
@Scope标注Bean的作用范围,scope取值singleton prototype request session globalsession

使用@Scope标注Bean的范围

//@Scope("prototype")@Scope("singleton")public class UserDaoImpl implements UserDao { //此处省略代码}

九、基于注解的IOC案例

(一)构建工程,添加依赖

<dependencies> <!--导入spring的context坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!--导入Jdbc模块依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!--导入Mysql 驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--导入C3P0连接池--> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!--导入junit单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency></dependencies>

(二)使用注解配置

@Repository(value = "userDao")public class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void save(User user) { String sql ="insert into user (name,birthday) values(?,?)"; jdbcTemplate.update(sql,user.getName(),user.getBirthday()); }}
@Service("userService")public class UserServiceImpl implements UserService { @Autowired private UserDao userDao ; @Override public void saveService(User user) { userDao.save(user); }}

(三)创建配置文件并开启对注解的支持

<context:component-scan base-package="com.offcn"></context:component-scan> <!--配置数据源--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property> <property name="user" value="root"></property> <property name="password" value="root"></property></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="dataSource"></constructor-arg></bean>

(四)编写测试代码

//IOC 注解版本的案例:@Testpublic void test1(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); User user = new User(); user.setName("admin"); user.setBirthday(new Date()); userService.saveService(user);}

十、纯注解配置

(一)新注解说明

注解说明
@Configuration用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定Spring在初始化容器时要扫描的包。作用和在Springdexml配置文件中的<context:component-scan base-package="com.offcn"/>一样
@Bean使用在方法上,标注将该方法的返回值存储到Spring容器中
@PropertySource用于加载xxx.properties文件中的配置
@Import用于导入其他配置类
  • @Configuration,@ComponentScan,@Import
@Configuration //指定当前类是一个配置类,取代applicationContext.xml配置文件@ComponentScan("com.offcn") //指定Spring在初始化容器时要扫描的包@Import({xxx.class}) //导入其他的配置类public class SpringConfiguration { ...}
  • @PropertySource,@Value
@PropertySource("classpath:dbConfig.properties") //当前类中引入dbConfig.properties文件public class DataSourceConfiguration { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password;}
  • @Bean
@Bean(name="dataSource") //将方法的返回值存入到IOC容器当中public DataSource getDataSource() throws Exception { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass(driver); dataSource.setJdbcUrl(url); dataSource.setUser(username); dataSource.setPassword(password); return dataSource;}

(二)通过注解获取容器

public void AnnotationTest (){ //使用AnnotationConfigApplicationContext获得ioc容器对象 ApplicationContext context= new AnnotationConfigApplicationContext(SpringConfig.class); Object obj = context.getBean("...");}

十一、Spring整合Junit

(一)IOC测试类中的问题和解决思路

在测试类中,每个测试方法都有一下两行代码:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = (UserService) context.getBean("userService");

这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。

(二)整合Junit配置步骤

1、添加技术依赖

<properties><spring.version>5.2.5.RELEASE</spring.version></properties><!--此处需要注意的是,spring5 及以上版本要求 junit 的版本必须是 4.12 及以上--><dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope></dependency><!--导入Spring整合Junit的依赖--><dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</arti
相关文档
  • Spring

  • 总结

  • 详解

相关文档推荐: