1. Spring
分层的Java SE/EE应用full-stack轻量级开源框架,以Ioc(反转控制)和AOP(面向切面编程)为内核。
1.1 Spring开发步骤
-
导入Spring的Maven坐标,重新加载项目
-
编写Dao接口和实现类
-
创建Spring核心配置文件(xml配置文件)
在resources目录下创建applicationContext.xml文件
-
在Spring配置文件中配置UserDaoImpl
-
使用Spring的API获得Bean实例
1.2 Spring配置文件
1.2.1 Bean标签基本配置
用于配置对象交给Spring创建,默认情况下调用无参构造函数,若没有无参构造函数则不能创建成功。
基本属性:
- id:Bean实例在Spring容器中的唯一标识。
- class:Bean的全限定名称。
1.2.2 Bean标签范围配置
scope:指对象的作用范围。
- singleton(默认值):
- Bean的实例化个数:1个。即在容器中只有一个对象,若创建多个对象则地址相同。
- Bean的实例化时机:当Spring的核心文件被加载时,实例化配置Bean的实例。
- Bean的生命周期:
- 对象创建:应用被加载时。
- 对象运行:容器存在的时候。
- 对象销毁:应用卸载,销毁容器时。
- prototype:
- Bean的实例化个数:多个。即在容器中只有一个对象,若创建多个对象则地址不同。
- Bean的实例化时机:调用getBean()方法时。
- Bean的生命周期:
- 对象创建:创建新的对象实例时。
- 对象运行:对象在使用中,就一直存在。
- 对象销毁:当对象长时间不使用时,被Java的垃圾回收器回收。
1.2.3 Bean生命周期配置
-
init-method:指定类中的初始化方法名称。
-
destroy-method:指定类中销毁方法名称。
1.2.4 Bean实例化三种方式
-
无参构造方法实例化(默认)
-
工厂静态方法实例化
-
工厂实例方法实例化(先获取工厂对象,再调用方法)
1.2.5 Bean的依赖注入
依赖注入(Dependency Injection)是Spring框架核心IOC的具体体现。
把dao和service之间的关系配置到容器中,降低其依赖关系(解耦)。使用Spring来维护业务层和持久层的依赖关系。
-
Bean的依赖注入方式
-
set方法注入
-
一般方法
<bean id="userService" class="com.kepler.service.impl.UserServiceImpl"> <!-- 把容器中的 UserDao 通过 UserService 内部的 setUserDao 方法注给 UserService --> <!-- 第一个"userDao"是service内部对象的属性名,第二个表示应用容器中id为"userDao"的Bean --> <property name="userDao" ref="userDao"></property> </bean>
-
P命名空间
xmlns:p="http://www.springframework.org/schema/p" <!-- 修改注入方式 --> <bean id="userService" class="com.kepler.service.impl.UserServiceImpl" p:userDao-ref="userDao"></bean>
-
-
有参构造注入
<bean id="userService" class="com.kepler.service.impl.UserServiceImpl"> <constructor-arg name="userDao" ref="userDao"></constructor-arg> </bean>
-
-
Bean的依赖注入的数据类型
- 普通数据类型
- 引用数据类型(Bean引入)
- 集合数据类型
1.2.6 引入其他配置文件(分模块开发)
实际开发中,Spring的配置内容非常多,这就导致Spring配置繁杂且体积庞大。所以,可以将部分配置拆解到其他配置文件中,而在Spring主配置文件通过 import 标签进行加载。
<import resources="applicationContext-xxx.xml"/>
1.2.7 Spring 的重点配置
<bean>标签
id属性:在容器中Bean实例的唯一标识
class属性:要实例化的Bean的全限定名
scope属性:Bean的作用范围,常用是Singleton(默认)和prototype
<property>标签:属性注入
name属性:属性名称
value属性:注入的普通属性值
ref属性:注入的对象引用值
<list>标签
<map>标签
<properties>标签
<constructor-arg>标签
<import>标签:导入其他的Spring的分文件
1.3 Spring相关API
1.3.1 ApplicationContext
ApplicationContext:接口类型,代表应用上下文,可以通过其实例获得Spring容器中的Bean对象。
-
ApplicationContext继承体系
-
ApplicationContext的实现类
- ClassPathXmlApplicationContext 从类的根路径下加载配置文件( 推荐)
- FileSystemXmlApplicationContext 从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
- AnnotationConfigApplicationContext 当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解
1.3.2 getBean()方法
-
getBean(String name)
表示根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。
-
getBean(Class requiredType)
表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,此方法会报错。
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService1 = (UserService) applicationContext.getBean("userService");
UserService userService2 = applicationContext.getBean(UserService.class);
1.3 Spring配置数据源
1.3.1 数据源(连接池)的作用和原理
- 数据源(连接池)用于提高程序性能
- 事先实例化数据源,初始化部分连接资源
- 使用连接时从数据源中获取
- 使用完毕后将连接资源归还给数据源
常见数据源(连接池):DBCP、C3P0、BoneCp、Druid等
1.3.2 数据源的开发步骤
- 导入数据源坐标和数据库驱动坐标
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
- 创建数据源对象(使用Spring配置)
① 导入坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.16</version>
</dependency>
② 创建Spring配置文件
在xml文件中加载properties文件
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
<?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">
<!-- 加载外部的 properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<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>
</beans>
③ 测试Spring容器产生数据源对象
@Test
// 测试Spring容器产生数据源对象
public void test4() throws Exception {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = app.getBean(DataSource.class);
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
- 设置数据源的基本连接数据
- 使用数据获取连接资源和归还连接资源
1.4 Spring 注解开发
1.4.1 Spring 原始注解
- 使用注解开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法
<!-- 配置组件扫描 -->
<context:component-scan base-package="com.kepler"/>
- 用注解替代配置
// <bean id="userDao" class="com.kepler.dao.Impl.UserDaoImpl"></bean>
//@Component("userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save running...");
}
}
//<bean id="userService" class="com.kepler.service.Impl.UserServiceImpl">
//@Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {
// <property name="userDao" ref="userDao"></property>
@Autowired // 自动注入,按照数据类型从Spring容器中进行注入
@Qualifier("userDao") // 按照id名称从容器中纪念性匹配,写要被注入的 bean的id,但此处需结合@Autowired一起使用
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
}
1.4.2 Spring 新注解
package com.kepler.config;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
// 标识该类时Spring的核心配置类
@Configuration
//<context:component-scan base-package="com.kepler"/>
@ComponentScan("com.kepler")
//<import resource=""/>
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}
package com.kepler.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
//<context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.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("dataSource") // Spring 会将当前方法的返回值以指定名称存储到 Spring 容器中
public DataSource getDataSource () throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
}
package com.kepler.web;
import com.kepler.config.SpringConfiguration;
import com.kepler.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class UserController {
public static void main(String[] args) {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = app.getBean(UserService.class);
userService.save();
}
}
1.5 Spring 整合 Junit
1.5.1 Spring集成Junit步骤
- 导入Spring集成Junit的坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.16</version>
</dependency>
- 使* 用@Runwith注解替换原来的运行期
- 使用@ContextConfiguration指定配置文件或配置类
- 使用@Autowired注入需要测试的对象
- 创建测试方法进行测试
package com.kepler.test;
import com.kepler.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
// @ContextConfiguration("classpath:applicationContext.xml") // 加载配置文件
@ContextConfiguration(classes = {SpringConfiguration.class}) // 全注解形式
public class SpringJunitTest {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.save();
}
}
1.6 Spring 集成 Web 环境
1.6.1 ApplicationContext应用上下文获取方式
应用上下文对象是通过new ClassPathXmlApplicationContext(Spring配置文件)
方式获取的,但每次从容器中获得Bean时,都要编写此代码,配置文件被加载多次,应用上下文对象创建多次。
在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在其存储到最大的域servletContext域中,即可在任意位置从域中获得应用上下文ApplicationContext对象了。
- 创建监听器
package com.kepler.listener;
import com.kepler.Service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
// 读取 web.xml中的全局参数
String contextConfiguration = servletContext.getInitParameter("contextConfiguration");
ApplicationContext app = new ClassPathXmlApplicationContext(contextConfiguration);
// 将 Spring 的应用上下文对象存储到ServletContext中
servletContext.setAttribute("app", app);
System.out.println("Spring 容器创建完毕...");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
ServletContextListener.super.contextDestroyed(sce);
}
}
- 配置web.xml
<!-- 全局初始化参数 -->
<context-param>
<param-name>contextConfiguration</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
<!-- 配置监听器 -->
<listener>
<listener-class>com.kepler.listener.ContextLoaderListener</listener-class>
</listener>
package com.kepler.listener;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
public class WebApplicationContextUtils {
public static ApplicationContext getWebApplicationContext(ServletContext servletContext) {
return (ApplicationContext) servletContext.getAttribute("app");
}
}
- 修改doGet
package com.kepler.web;
import com.kepler.Service.UserService;
import com.kepler.listener.WebApplicationContextUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
// ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService userService = app.getBean(UserService.class);
userService.save();
}
}
1.6.2 Spring 提供获取应用上下文的工具
以上分析不用手动实现,Spring提供一个监听器ContextLoaderListener就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象
- 导入spring-web依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.10</version>
</dependency>
- 在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
<!-- 全局初始化参数 -->
<context-param>
<param-name>contextConfiguration</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 配置监听器 -->
<listener>
<listener-class>com.kepler.listener.ContextLoaderListener</listener-class>
</listener>
- 使用WebApplicationContextUtils获得上下文对象ApplicationContext
package com.kepler.web;
import com.kepler.Service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService userService = app.getBean(UserService.class);
userService.save();
}
}