Spring学习笔记(一)
一 、Spring概述
(一)Spring是什么
Spring是一个分层的Java SE/EE full-stack(一站式)轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。
在java三层架构当中分别提供了相应技术:
表现层(web层) :SpringMVC 框架
业务层(service层) :Bean管理(IOC容器)
持久层(dao层) :JdbcTemplate模板对象以及提供了ORM模块整合其他优秀的持久层技术
(二)Spring框架发展历程
1997 年, IBM提出了EJB 的思想
1998 年,SUN制定开发标准规范 EJB1.0
1999 年,EJB1.1 发布
2001 年,EJB2.0 发布
2003 年,EJB2.1 发布
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,Quartz等)的直接支持
javaEE技术的封装 :Spring对javaEE开发当中复杂难用的API(JavaEmail, RMI等)进行封装,降低了这些API的使用难度
(四)SpringFrameWork系统结构
二、 程序的耦合和解耦合
(一)什么是程序的耦合
程序的耦合是程序之间的关联性,也就是多个类的联系是否紧密,多个对象之间的关系是否密切。
生活中的案例:
你的房子里面有窗子,那么房子和窗子就有了关联
耦合度是松还是紧就看你的关联是强还是弱,也就是修改的代价,比如你窗子是扣死在墙里的那么你修改窗子就必须修改墙 这就比较紧密了,反应在程序上就是耦合度高,不利于程序的扩展和维护。
但是如果你窗子是按照某种规格的 可以自由拆装的,那么修改的代价就小,耦合度也就低了,反应在程序上就是耦合度低,利于程序的扩展和维护。
我们写程序的目标就是 高内聚 低耦合!
这样修改起来 就不会有太多的联系,不用改一个地方其他的都要修改。
(二)解决程序耦合的思路
1.编译不依赖,运行时才依赖
当我们讲解jdbc时,是通过反射来注册驱动的,代码如下:
Class.forName("com.mysql.jdbc.Driver");//使用的驱动类是指定了一个字符串
此时的好处是,我们的类中在编译阶段不再需要具体的驱动类,就算删除mysql的驱动jar包,依然可以通过编译。在运行阶段才会依赖驱动包。实际开发当中,我们应该做到编译不依赖,运行时才依赖。
上述代码产生的新问题,mysql驱动类的全限定类名作为一个字符串java类中是写死的,一旦发生改变,还需要修改源码。
使用配置文件结合反射就可以解决上述问题。
2.使用工厂模式解耦合
在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的 方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。
那么,这个读取配置文件,创建和获取三层对象的类就是工厂。
三、SpringIOC机制详解
(一)IOC概述及作用
1.IOC的简介及设计思想
SpringIOC:IOC 是 Inversion of Control 的缩写,多数书籍翻译成“控制反转”,还有些书籍翻译成为“控制反向”或者“控制倒置”。
1996 年,Michael Mattson 在一篇有关探讨面向对象框架的文章中,首先提出了 IOC 这个概念。简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。
IOC 理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦 如下图
大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了, 全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合 在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。
我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:
我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话, 当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,这将是 一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系!
2.IOC作用
IOC本质上就是一个大工程,大容器。主要作用就是创建和管理对象的依赖关系,削减计算机程序的耦合(解除我们代码中的依赖关系),提高程序的可扩展性和可维护性。
四、 SpringIOC入门案例
1.构建maven工程,添加Spring依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jn</groupId>
<artifactId>SpringFrameWorkProject01</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<!--导入spring的context坐标,context依赖core、beans、expression、apo-->
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
</dependencies>
</project>
2.创建持久层接口和实现类
UserDao
package com.jn.dao;
public interface UserDao {
public void save();
}
UserDaoImpl
package com.jn.dao.Impl;
import com.jn.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDao saving...");
}
}
3.创建业务层接口和实现类
UserService
package com.jn.service;
public interface UserService {
public void saveService();
}
UserServiceImpl
package com.jn.service.Impl;
import com.jn.service.UserService;
public class UserServiceImpl implements UserService {
@Override
public void saveService() {
System.out.println("service saving...");
}
}
4.resources创建ApplicationContext.xml
5.配置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.jn.dao.Impl.UserDaoImpl"></bean>
<!--配置UserServiceImpl 对象-->
<bean id="userService" class="com.jn.service.Impl.UserServiceImpl"></bean>
</beans>
6.测试IOC 配置
package com.jn;
import com.jn.dao.UserDao;
import com.jn.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IOCTest {
//测试IOC容器是否配置成功
@Test
public void test(){
//1、获取Spring IOC对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2、从容器中根据id获得UserDaoImpl对象,执行UserDao的save方法
UserDao userDao = (UserDao) context.getBean("userDao");
userDao.save();
//2、从容器中根据id获得UserServiceImpl对象,执行UserService的saveService方法
UserService userService = (UserService) context.getBean("userService");
userService.saveService();
}
}
运行结果:
项目整体结构图展示
五、Spring基于XML的IOC细节
1.IOC配置文件详解
bean标签
用于配置对象交给Spring 来创建。默认情况下他会调用类中无参数的构造器,如果没有无参数构造器则不能成功创建
基本属性
id : Bean实例对象在Spring容器当中的唯一标识
class: Bean 的全限定类名
2 SpringIOC机制源码解析
2.1 IOC容器解析
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂,Spring 中工厂的类结构图如下:
BeanFactory
IOC容器的基本实现,是Spring内部使用的接口,不提供开发人员使用,加载配置文件时,不 会创建对象,在获得(使用)对象时才采取创建对象。
HierarchicalBeanFactory
这个工厂接口非常简单,实现了Bean工厂的分层。 工厂接口也是继承自BeanFacotory,也是一个二级接口,相对于父接口,它只扩展了一个重要的功能——工厂分层
AutowireCapableBeanFactory
该接口有自动装配能力,需要注意的是,ApplicationContext接口并没有实现此接口,因为应用代码很少用到此功能,如果确实需要的话,可以调用ApplicationContext的getAutowireCapableBeanFactory方法,来获取此接口的实例。
ListableBeanFactory
获取bean时,Spring 鼓励使用这个接口定义的api,如查看Bean的个数、获取某一类型Bean的配置名、查看容器中是否包括某一Bean等方法。
ApplicationContext
BeanFactory接口的子接口,提供更多强大的功能,一般由开发人员使用.接口提供了bean基础性操作同时,扩展了国际化等功能。ApplicationContext接口在加载配置文件时候就会配置文件当中的对象进行创建,存放在IOC容器当中
AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件 推荐使用这种
FileSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
2.2 IOC容器底层bean初始化过程
BeanFactoryPostProcessor
作用:定义了在bean工厂对象创建后,bean对象创建前执行的动作,用于对工厂进行创建后业务处理
运行时机: 操作用于对工厂进行处理,仅运行一次
BeanPostProcessor
作用: 定义了所有bean初始化前后进行的统一动作,用于对bean进行创建前业务处理与创建后业务处理
运行时机:当前操作伴随着每个bean的创建过程,每次创建bean均运行该操作
InitializingBean
作用:定义了每个bean的初始化前进行的动作,属于非统一性动作,用于对bean进行创建前业务处理。类似于init-method。
运行时机:当前操作伴随着任意一个bean的创建过程,保障其个性化业务处理
六、手动实现自己的IOC容器
1.分析IOC 实现思路
流程解析:
根据路径、资源名称等方式,将xml文件、注解类加载到容器中
通过BeanDefinitionReader将对象解析成BeanDefinition实例
创建BeanFactory工厂(注册前后需要添加bean前置、后置处理器)
通过BeanFactory工厂将对象实例化、对象初始化(初始化前后执行前置、后置处理器
2.IOC原理实现-环境搭建:构建maven工程,引入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<!--导入spring的context坐标,context依赖core、beans、expression、apo-->
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
</dependencies>
3.设计接口类和配置文件
UserDao
package com.jn.dao;
public interface UserDao {
public void save();
}
UserDaoImpl
package com.jn.dao.impl;
import com.jn.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDao Saving...");
}
}
配置UserDaoImpl
<?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.jn.dao.impl.UserDaoImpl"></bean>
</beans>
4.解析配置文件
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
5.创建自己的工厂类
package com.jn.factory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MyBeanFactory {
//创建一个map集合,模拟IOC容器
private static Map<String, Object> map = new HashMap<>();
//使用dom4j解析xml文件
static {
try{
//1、获得一个解析器
SAXReader saxReader = new SAXReader();
//2、读取外部的配置文件
String path = "src/main/resources/ApplicationContext.xml";
//3、读取了整个文档对象
Document document = saxReader.read(path);
//4、获得根节点
Element rootElement = document.getRootElement();
//5、获得根节点下的所有bean标签对应的节点
List<Element> bean =rootElement.elements("bean");
for (Element element : bean) {
String id = element.attributeValue("id");
String clazz = element.attributeValue("class");
//6、通过反射创建对象
Class clz = Class.forName(clazz);
Object object =clz.newInstance();
//7、将创建好的对象,放入map集合中
map.put(id,object);
}
}catch (Exception e){
e.printStackTrace();
}
}
//根据id从容器里面获得对象
public static Object getBean(String id){
Object object = map.get(id);
return object;
}
}
6..编写测试文件,展示测试结果
package com.jn;
import com.jn.dao.UserDao;
import com.jn.factory.MyBeanFactory;
import org.junit.Test;
public class IOCTest {
@Test
public void test(){
//1、创建工厂对象
MyBeanFactory factory = new MyBeanFactory();
//从容器中根据id获得对象
UserDao userDao = (UserDao) factory.getBean("userDao");
System.out.println(userDao);
userDao.save();
}
}
七、bean的实例化
(一)、bean实例化介绍
(二)、bean实例化方式
1、构造方法的方式
它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。
1.1创建User类
package com.jn.pojo;
public class User {
//构造方法实现Bean的实例化
public User(){
System.out.println("Constructor Function Bean");
}
}
1.2管理user 类型对象
<!--构造函数方法实现Bean的实例化配置-->
<bean id="user" class="com.jn.pojo.User"></bean>
1.3测试
//测试构造方法实现Bean的实例化
@Test
public void testConstructorBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user);
}
2、静态工厂方式
2.1 创建静态工厂ItemFactory
package com.jn.factory;
import com.jn.pojo.User;
public class ItemFactory {
//静态方式实现Bean的实例化
public static User createUser() {
System.out.println("Static method running creat bean");
return new User();
}
}
2.2 管理User类型对象
<!--静态工厂方式实现Bean的实例化-->
<bean id="staticBean" class="com.jn.factory.ItemFactory" ></bean>
2.3 测试
//测试静态方法方法实现Bean的实例化
@Test
public void testStaticBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
ItemFactory itemFactory = (ItemFactory) context.getBean("staticBean");
itemFactory.createUser();
}
3、实例工厂方式
3.1 创建实例工厂NewItemFactory
package com.jn.factory;
import com.jn.pojo.User;
public class NewItemFactory {
//实例化工厂实现Bean的实例化
public User createUser() {
System.out.println("Dynamic method running creat bean");
return new User();
}
}
3.2 管理NewItemFactory类型对象
<!--实例化工厂方式实现Bean的实例化-->
<bean id="nweItemFactory" class="com.jn.factory.NewItemFactory" ></bean>
<bean id="user" factory-bean="nweItemFactory" factory-method="createUser"></bean>
3.3 测试
//测试实例化工厂方法方法实现Bean的实例化
@Test
public void testDynamicBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
NewItemFactory itemFactory = (NewItemFactory) context.getBean("nweItemFactory");
itemFactory.createUser();
}
4、FactoryBean实例化Bean
4.1创建UserDao接口
package com.jn.dao;
public interface UserDao {
public void save();
}
4.2定义UserDaoImpl类
package com.jn.dao.impl;
import com.jn.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDao Saving...");
}
}
4.3管理UserDao接口对象
<!--使用FactoryBean实例化Bean-->
<bean id="userDaoFactoryBean" class="com.jn.factory.UserDaoFactoryBean"></bean>
4.4测试
//使用FactoryBean实例化Bean的测试
@Test
public void testFactoryBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
UserDao userDao1 = (UserDao) context.getBean("userDaoFactoryBean");
UserDao userDao2 = (UserDao) context.getBean("userDaoFactoryBean");
//测试是否是单例模式创建——UserFactoryBean里面设置为了非单例
System.out.println(userDao1);
System.out.println(userDao2);
userDao1.save();
userDao2.save();
}
实例化Bean项目总体结构
八、bean作用域
(一)、bean作用域介绍
所谓Bean的作用域其实就是指Spring给我们创建出的对象的存活范围,在配置文件中通过bean的scope属性指定
scope:指对象的作用范围,取值如下:
取值范围 | 说明 |
singleton | 默认值,单例的 |
prototype | 多例的 |
request | WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中 |
session | WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中 |
global session | WEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session |
(二)、bean作用域的解析
1.scope值为singleton
Bean的实例化个数:1个
Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
2.scope值为prototype
Bean的实例化个数:多个
Bean的实例化时机:当调用getBean()方法时实例化Bean
3.Scope为其他值
scope指定为其他值,需要在特定的环境下使用, 只需要作为一个了解知识,面试能够回答出来即可
九、Bean的生命周期
(一)、Bean的生命周期概括
在Spring框架中,Bean的生命周期是指从创建Bean实例开始,到最终被销毁的整个过程。这个过程由Spring的IoC容器进行管理,涉及到多个阶段和扩展点,允许开发者在Bean的生命周期的不同阶段进行干预和自定义操作。
(二)、Bean生命周期的演示
1.UserDaoImpl中添加函数
使用内置对象的方式实现周期控制
package com.jn.dao.Impl;
import com.jn.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDao saving...");
}
public void init(){
System.out.println("init...");
}
public void destory(){
System.out.println("destory...");
}
}
2.修改UserServiceImpl
使用接口的方式实现周期的控制
package com.jn.service.Impl;
import com.jn.dao.UserDao;
import com.jn.service.UserService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class UserServiceImpl implements UserService , InitializingBean, DisposableBean {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void saveService() {
System.out.println("service saving...");
}
public void destroy() throws Exception {
System.out.println("Service Destory");
}
public void afterPropertiesSet() throws Exception {
System.out.println("Service Init");
}
}
3. 配置对象
<!--测试Bean的生命周期实现的配置-->
<!--配置UserDaoImpl 对象
init-method:设置bean初始化生命周期回调函数
destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象-->
<bean id="userDao" class="com.jn.dao.Impl.UserDaoImpl" init-method="init" destroy-method="destory"></bean>
<!--配置UserServiceImpl 对象-->
<bean id="userService" class="com.jn.service.Impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
4.测试
//测试Bean的生命周期
@Test
public void testEeanLife(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
userDao.save();
context.close();
}
5.测试结果分析
首先,当 Spring 容器启动时,会根据配置创建 `userDao` Bean,并通过指定的 `init-method` 调用 `UserDaoImpl` 中的 `init` 方法,打印出“init...”进行初始化。
接着创建 `userService` Bean,在这个过程中,通过配置文件将 `userDao` 注入到 `userService` 中,触发 `setUserDao` 方法打印“set...”。
同时,由于 `userService` 实现了 `InitializingBean` 接口,在属性设置完成后,容器会调用其 `afterPropertiesSet` 方法,打印“Service Init”进行进一步初始化。
在测试方法中,获取 `userDao` 对象并调用其 `save` 方法,执行 `UserDaoImpl` 中的对应方法,打印“UserDao saving...”。 当测试方法执行 `context.close()` 关闭 Spring 容器时,对于实现了 `DisposableBean` 接口的 `userService` Bean,会调用其 `destroy` 方法,打印“Service Destory”进行销毁操作。
同时,根据配置文件中指定的 `destroy-method`,也会调用 `UserDaoImpl` 的 `destory` 方法,打印“destory...”完成 `userDao` 的销毁。
十、Spring依赖注入
(一)、依赖注入的介绍
依赖注入(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。
IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取
(二)、构造函数注入
1.构建Account类
顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 Spring 框架来为我们注入。具体代码如下
package com.jn.pojo;
import java.io.Serializable;
import java.util.Date;
public class Account implements Serializable {
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;
}
@Override
public String toString() {
return "Account{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}
}
2.配置Account类
<!--构造函数注入的配置
要求:类中需要提供一个对应参数列表的构造器函数
涉及的标签:
constructor-arg:
属性:
name: 执行参数在构造器中的名称
value:它能赋的值是基本数据类型和 String 类型
ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
-->
<bean id="time" class="java.util.Date"></bean>
<bean id="account" class="com.jn.pojo.Account">
<constructor-arg name="name" value="王思梦"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="time"></constructor-arg>
</bean>
3.测试
//构造函数方法注入测试
@Test
public void testConstructInsertFunction(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//根据Id得到对象Account
Account account = (Account) context.getBean("account");
System.out.println(account);
}
(三)、setter注入
2.1 Account类添加setter
顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:
package com.jn.pojo;
import java.io.Serializable;
import java.util.Date;
public class Account implements Serializable {
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;
}
@Override
public String toString() {
return "Account{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}
}
2.2 配置Account类
<!--
使用setter方法的方式给属性赋值
涉及的标签:
property
属性:
name:找的是类中set方法后面的部分
ref: 给属性赋值是其他bean类型的
value:给属性赋值是基本数据类型和 string 类型的
实际开发当中, 此种方式用的比较多,推荐使用
-->
<bean id="noeTime" class="java.util.Date"></bean>
<bean id="setterFunction" class="com.jn.pojo.Account">
<property name="name" value="铁头"></property>
<property name="age" value="18"></property>
<property name="birthday" ref="noeTime"></property>
</bean>
2.3 测试
//setter注入方法的测试
@Test
public void testSettetInsertFunction(){
//得到ClassPathXmlApplicationContext对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//通过ClassPathXmlApplicationContext对象得到Account的实体化对象
Account account = (Account) context.getBean("setterFunction");
System.out.println("name:"+account.getName()+"\tage:"+account.getAge()+"\tbirthday:"+account.getBirthday());
}
(四)、注入集合数据
3.1 修改Account类
顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。
这里注入数组,List,Set,Map,Properties。具体代码如下:
/*
输入集合的Spring依赖测试
*/
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
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;
}
3.2 配置Account类
<!-- 注入集合类型的数据测试-->
<bean id="listAccount" class="com.jn.pojo.Account">
<!--注入数组数据-->
<property name="myStrs">
<array>
<value>王思梦</value>
<value>铁头</value>
<value>铁头铁头,下雨不愁,人家有伞,我有铁头</value>
</array>
</property>
<!--注入list数据-->
<property name="myList">
<list>
<value>紫霞</value>
<value>白晶晶</value>
<value>至尊宝</value>
</list>
</property>
<!--注入map数据-->
<property name="myMap">
<map>
<entry key="name" value="萧炎"></entry>
<entry key="age">
<value>26</value>
</entry>
</map>
</property>
<!--注入set数据-->
<property name="mySet">
<list>
<value>小医仙</value>
<value>古熏儿</value>
<value>美杜莎</value>
</list>
</property>
<!--注入properties集合-->
<property name="myProps">
<props>
<prop key="gender">男</prop>
<prop key="kongfu">佛怒火连</prop>
</props>
</property>
</bean>
3.3 测试
//测试注入集合的方式添加Spring依赖
@Test
public void testListInsertFunction(){
//获得ClassPathXmlApplicationContext对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//通过ClassPathXmlApplicationContext对象得到Account的实体化对象
Account account = (Account) context.getBean("listAccount");
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());
}
十一、Spring配置文件模块化
(一)、 Spring模块化的介绍
我们现在的配置都集中配在了一个ApplicationContext.xml文件中,当开发人员过多时, 如果所有bean都配置到同一个配置文件中,会使这个文件巨大,而且也不方便维护。 针对这个问题,Spring提供了多配置文件的方式,也就是所谓的配置文件模块化。
(二)、Spring模块化的配置
1、Spring模块化配置方式一
并列的多个配置文件 直接编写多个配置文件,比如说beans1.xml,beans2.xml......, 然后在创建ApplicationContext的时候,直接传入多个配置文件。
ApplicationContext context = new ClassPathXmlApplicationContext("Account.xml","UserDao.xml","...");
1.1新建Account.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注入集合类型的数据测试-->
<bean id="listAccount" class="com.jn.pojo.Account">
<!--注入数组数据-->
<property name="myStrs">
<array>
<value>王思梦</value>
<value>铁头</value>
<value>铁头铁头,下雨不愁,人家有伞,我有铁头</value>
</array>
</property>
<!--注入list数据-->
<property name="myList">
<list>
<value>紫霞</value>
<value>白晶晶</value>
<value>至尊宝</value>
</list>
</property>
<!--注入map数据-->
<property name="myMap">
<map>
<entry key="name" value="萧炎"></entry>
<entry key="age">
<value>26</value>
</entry>
</map>
</property>
<!--注入set数据-->
<property name="mySet">
<list>
<value>小医仙</value>
<value>古熏儿</value>
<value>美杜莎</value>
</list>
</property>
<!--注入properties集合-->
<property name="myProps">
<props>
<prop key="gender">男</prop>
<prop key="kongfu">佛怒火连</prop>
</props>
</property>
</bean>
</beans>
1.2新建UserDao.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置UserDaoImpl-->
<bean id="userDao" class="com.jn.dao.impl.UserDaoImpl"></bean>
</beans>
1.3测试
//测试程序的模块化
@Test
public void testModularization(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Account.xml","UserDao.xml");
//通过context对象得到UserDao实体对象
UserDao userDao = (UserDao) context.getBean("userDao");
//通过context对象得到Account的实体化对象
Account account = (Account) context.getBean("listAccount");
userDao.save();
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());
}
2、Spring模块化配置方式二
主从配置文件 先配置一个主配置文件,然后在里面导入其它的配置文件。
<import resource="Account.xml" />
<import resource="UserDao.xml" />
注意:
同一个xml文件中不能出现相同名称的bean,如果出现会报错
多个xml文件如果出现相同名称的bean,不会报错,但是后加载的会覆盖前加载的bean,所以企业开发中尽 量保证bean的名称是唯一的。
2.1 引入到主配置文件
<import resource="Account.xml"></import>
<import resource="UserDao.xml"></import>
2.2测试
//测试程序的模块化
@Test
public void testModularization(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//通过context对象得到UserDao实体对象
UserDao userDao = (UserDao) context.getBean("userDao");
//通过context对象得到Account的实体化对象
Account account = (Account) context.getBean("listAccount");
userDao.save();
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());
}
项目整体目录结构
十二、模板设计模式解析
(一)、模板设计模式介绍
模板方法(Template Method)模式的定义如下:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式
模板方法模式的静态结构图如下:
(二)、模板设计模式的应用场景
在多个子类中拥有相同的方法,而且逻辑相同时,可以将这些方法抽出来放到一个模板抽象类中程序主框架相同,细节不同的情况下,也可以使用模板方法
举例说明:
a:使用过Servlet的人都清楚,除了要在web.xml做相应的配置外,还需继承一个叫HttpServlet的抽象类。HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体子类提供,因此这是典型的模板方法模式。
b:持久层对数据库的操作,Spring提供了JdbcTemplate模板对象, 完成CRUD操作。
(三)、出国留学手续设计程序
1.需求
分析:出国留学手续一般经过以下流程:索取学校资料,提出入学申请,办理因私出国护照、出境卡和公证,申请签证,体检、订机票、准备行装,抵达目标学校等,其中有些业务对各个学校是一样的,但有些业务因学校不同而不同,所以比较适合用模板方法模式来实现。
在本实例中,我们先定义一个出国留学的抽象类 StudyAbroad,里面包含了一个模板方法 TemplateMethod(),该方法中包含了办理出国留学手续流程中的各个基本方法,其中有些方法的处理由于各国都一样,所以在抽象类中就可以实现,但有些方法的处理各国是不同的,必须在其具体子类(如美国留学类 StudyInAmerica)中实现。如果再增加一个国家,只要增加一个子类就可以了。
2.程序代码实现
2.1父类的实现
package com.jn.template;
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 void templateMethod(){
LookingForSchool();
ApplyForEnrol();
ApplyForPassport();
ApplyForVisa();
ReadyGoAbroad();
Arriving();
}
}
2.2子类的定义
定义具体的子类,美国留学
package com.jn.template;
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)了解校园及周边环境。");
}
}
2.3测试
package com.jn.template;
public class StudyAbroadProcess {
public static void main(String[] args) {
StudyAbroad tm = new StudyInAmerica();
tm.templateMethod();
}
}
项目整体结构目录
原文地址:https://blog.csdn.net/m0_67226963/article/details/143487686
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!