一、Spring 简介
概念
Spring 是目前主流的 Java Web 开发框架
,是 Java 世界最为成功的框架。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力。Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力
。
它包括很多框架,如Spring framework、SpringMVC、SpringBoot、Spring Cloud、Spring Data、Spring Security等。有人将它们亲切的称为:Spring全家桶。
Spring framework就是我们平时说的Spring框架,它是全家桶中其他框架的基础与核心。
核心
Spring是分层的Java SE/EE一站式轻量级开源框架,以IOC(Inverse of Control)与AOP(Aspect Oriented Programming)为内核。
IOC控制反转指的是对象的创建不在需要程序员,而是通过Spring帮助我们创建,通过Spring创建的对象称之为Bean,它由Spring的IOC容器管理。
AOP面向切面编程用于封装多个类的公共行为,减少重复的业务代码。如日志、事务、权限等就用到了AOP。
Spring致力于为JavaEE应用各层提供解决方案,通过其本身的粘合性。在表现层可以整合SpringMVC、Struts2,在业务层可以管理事务和记录日志等,持久层可以整合Mybatis、Hibernate、JdbcTemplate等技术。
二、Spring体系结构
Spring框架采用分层的理念,根据功能的不同划分为多个模块。
1、Data Access/Integration(数据访问/集成)
数据访问/集成层包括JDBC、ORM、OXM、JMS和Transactions模块、
JDBC模块:提供了一个JDBC的样例模板,使用这些模板能够消除冗长的JDBC编码还有必须的事务控制。
ORM模块:提供与流行的“对象-关系”映射框架无缝集成的API,包括JPA、JDO、Hibernate和Mybatis等。而且还可以使用Spring事务管理,无需额外控制事务。
2、Web模块
Web 模块:提供了基本的 Web 开发集成特性,例如多文件上传功能、使用的 Servlet 监听器的 IOC 容器初始化以及 Web 应用上下文。
Servlet 模块:提供了一个 Spring MVC Web 框架实现。Spring MVC 框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的 JSP 标签,完全无缝与 Spring 其他技术协作。
WebSocket 模块:提供了简单的接口,用户只要实现响应的接口就可以快速的搭建 WebSocket Server,从而实现双向通讯。
Portlet 模块:提供了在 Portlet 环境中使用 MVC 实现,类似 Web-Servlet 模块的功能。
3、 Core Container(Spring的核心容器)
Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成,没有这些核心容器,也不可能有 AOP、Web 等上层的功能。
Beans 模块:提供了框架的基础部分,包括控制反转和依赖注入。
Core 核心模块:封装了 Spring 框架的底层部分,包括资源访问、类型转换及一些常用工具类。
Context 上下文模块:建立在 Core 和 Beans 模块的基础之上,集成 Beans 模块功能并添加资源绑定、数据验证、国际化、Java EE 支持、容器生命周期、事件传播等。ApplicationContext 接口是上下文模块的焦点。
SpEL 模块:提供了强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从 Spring 容器获取 Bean,它也支持列表投影、选择和一般的列表聚合等。
4、 AOP、Aspects、Instrumentation和Messaging
在 Core Container 之上是 AOP、Aspects 等模块,具体介绍如下:
AOP 模块:提供了面向切面编程实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中,这样各司其职,降低业务逻辑和通用功能的耦合。
Aspects 模块:提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程(AOP)框架。
Instrumentation 模块:提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
messaging 模块:Spring 4.0 以后新增了消息(Spring-messaging)模块,该模块提供了对消息传递体系结构和协议的支持。
5.、Test模块
Test 模块:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。
三、Spring IOC
IoC 容器是 Spring 的核心,也可以称为 Spring 容器。Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期。
Spring提供了2中不同类型的IOC容器。
BeanFactory容器
BeanFactory 是最简单的容器,由 org.springframework.beans.factory.BeanFactory 接口定义,采用懒加载(lazy-load),所以容器启动比较快。BeanFactory 提供了容器最基本的功能。
为了能够兼容 Spring 集成的第三方框架(如 BeanFactoryAware、InitializingBean、DisposableBean),所以目前仍然保留了该接口。
BeanFactory最常见的实现类org.springframework.beans.factory.xml.XmlBeanFactor
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ApplicationContext容器
ApplicationContext 继承了 BeanFactory 接口,由org.springframework.context.ApplicationContext 接口定义,对象在启动容器时加载。ApplicationContext 在 BeanFactory 的基础上增加了很多企业级功能,例如 AOP、国际化、事件支持等。
ApplicationContext有两个常用的实现类
(1)ClassPathXmlApplicationContext
该类从类路径 ClassPath 中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作,具体如下所示。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);
(2)FileSystemXmlApplicationContext
该类从指定的文件系统路径中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作,具体如下所示。
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);
它与 ClassPathXmlApplicationContext 的区别是:在读取 Spring 的配置文件时,FileSystemXmlApplicationContext 不会从类路径中读取配置文件,而是通过参数指定配置文件的位置。即 FileSystemXmlApplicationContext 可以获取类路径之外的资源,如“F:/workspaces/Beans.xml”。
通常在 Java 项目中,会采用 ClassPathXmlApplicationContext 类实例化 ApplicationContext 容器的方式,而在 Web 项目中,ApplicationContext 容器的实例化工作会交由 Web 服务器完成。Web 服务器实例化 ApplicationContext 容器通常使用基于 ContextLoaderListener 实现的方式,它只需要在 web.xml 中添加如下代码:
<!--指定Spring配置文件的位置,有多个配置文件时,以逗号分隔-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!--spring将加载spring目录下的applicationContext.xml文件-->
<param-value>
classpath:spring/applicationContext.xml
</param-value>
</context-param>
<!--指定以ContextLoaderListener方式启动Spring容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
需要注意的是,BeanFactory 和 ApplicationContext 都是通过 XML 配置文件加载 Bean 的。
二者的主要区别在于,如果 Bean 的某一个属性没有注入,使用 BeanFacotry 加载后,第一次调用 getBean() 方法时会抛出异常,而 ApplicationContext 则会在初始化时自检,这样有利于检查所依赖的属性是否注入。
因此,在实际开发中,通常都选择使用 ApplicationContext,只有在系统资源较少时,才考虑使用 BeanFactory。本教程中使用的是 ApplicationContext 容器。
四、Spring Bean的管理
Bean是存储在Spring容器中的对象,我们可以使用xml或注解完成它的注入。
1、使用xml文件注入Bean
1.Bean对象的属性类型配置:
- 八大基本数据类型
<!--普通属性-->
<property name="name" value="小明"/>
- 数组类型
<!--String[]-->
<property name="books">
<array>
<value>水浒传</value>
<value>三国演义</value>
<value>红楼梦</value>
</array>
</property>
- 集合类型
<!--List-->
<property name="hobby">
<list>
<value>打球</value>
<value>唱歌</value>
<value>学习</value>
</list>
</property>
- 对象类型
<bean id="address" class="com.kuang.pojo.Address">
<property name="address" value="湖南省株洲市"/>
</bean>
<!--bean注入,使用ref属性-->
<property name="address" ref="address"/>
- Map
<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="1244566...."/>
<entry key="银行卡" value="2345674...."/>
</map>
</property>
- Set
<!--Set-->
<property name="games">
<set>
<value>跳大绳</value>
<value>王者荣耀</value>
</set>
</property>
- Properties
<property name="info">
<props>
<prop key="url">jdbc:mysql://localhost:3306/test?useUnicode=true...</prop>
<prop key="name">...</prop>
<prop key="password">...</prop>
</props>
</property>
2.设置Bean的作用域(Scopes)
1.singleton单例模式(Bean的默认模式),每次get得到的对象都是同一个。
<bean id="a0" class="com.kuang.pojo.Address" p:address="株洲" scope="singleton"/>
2.prototype原型模式,每次get到的对象都是不同的。
<bean id="a1" class="com.kuang.pojo.Address" p:address="株洲" scope="prototype"/>
3.request、session、application,这些只能在web开发中使用到!
2、使用注解完成Bean的注入
我们可以通过@Component注解将类定义为一个Bean组件,从而完成Bean的注入。
例:
package com.kuang.pojo;
@Component //定义为一个bean组件
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
//定义属性值
@Value(value = "秦疆")
public void setName(String name) {
this.name = name;
}
}
在Spring配置文件中扫描该组件完成组件的注入。
<context:component-scan base-package="com.kuang.pojo"/>
与@Component作用相同的注解还有@Repository、@Service、@Controller,这些注解是为了能够更好的辨识我们的类。
@Repository 用在dao层的类上
@Service 用在service层的类上
@Controller 用在controller层的类上
@Component 用在实体类或其他需要注入到Spring容器中的类上
我们也可以使用注解自动装配容器中已有的Bean
@Autowired和@Resources都可以实现属性是Bean的自动装配功能,通常放在set方法或构造方法上。
注解 | @Autowired | @Resource |
---|---|---|
注入方式 | byType(按照类名) | byName(按照id) |
注入特定的Bean | 使用@Qualifier注解 | 使用name属性指定 |
使用xml与注解配置bean的区别在于,xml更加万能,维护更加简单方便。最佳的开发实践是使用xml来管理bean,注解负责完成属性的注入。
五、Bean的生命周期
六、Spring AOP面向切面编程
1、什么是AOP
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,利用AOP可以对业务逻辑的各个部分进行隔离,在业务类中插入服务代码,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
它可以保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。
2、AOP在Spring中的作用
提供声明式事务:允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
- 切面(Aspect):横切关注点被模块化的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 "地点"的定义
- 连接点(JointPoint):与切入点匹配的执行点。
3、Spring中实现AOP织入的方式
【重点】使用AOP织入,需要导入一个依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
实现AOP织入的方式一:使用Spring 原生的API
public interface UserService {
void add();
void delete();
void select();
void update();
}
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void select() {
System.out.println("查询了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
}
前置织入
public class Log implements MethodBeforeAdvice {
//method: 要执行的目标对象的方法
//args:参数
//target:目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
}
}
后置织入
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + method.getName() + "返回的结果为:" + returnValue);
}
}
application.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log"/>
<bean id="afterLog" class="com.kuang.log.AfterLog"/>
<!--方式一:使用原生的Spring API接口-->
<!--配置aop:需要导入aop的约束-->
<aop:config>
<!--切入点:expression:表达式 execution(要执行的位置! * * * * *)-->
<aop:pointcut id="pointCut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加!-->
<aop:advisor advice-ref="log" pointcut-ref="pointCut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointCut"/>
</aop:config>
</beans>
测试
@Test
public void t(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
//动态代理代理的是接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
实现AOP织入的方式二:使用自定义类实现AOP织入
自定义一个ascept切面类。
public class DiyPointCut {
public void before(){
System.out.println("========方法执行前=======");
}
public void after(){
System.out.println("========方法执行后=======");
}
}
<!--方式二:使用自定义类-->
<bean id="diy" class="com.kuang.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面,ref要引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
以上两种AOP的实现方式一个是接口实现,一个是切面定义。
实现AOP织入的方式三:使用注解实现
//方式三:使用注解方式实现AOP
@Aspect
public class AnnotationPointCut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("====方法执行前====");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("====方法执行后====");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Signature signature = jp.getSignature();//获得方法签名
System.out.println("Signature:" + signature);
//执行方法
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
<!--方式三-->
<bean id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
AOP概念:
1.切面(aspect):跨越多个类的关注点的模块块,织入的内容。
2.连接点(JoinPoint):程序执行过程中的一个点,在 Spring AOP 中,一个连接点总是代表一个方法的执行。
3.通知(advice):方面在特定连接点采取的行动。
4.切入点(PointCut):连接点表达式匹配的一组连接点。
5.目标对象(Target object):被一个或多个方面通知的对象。由于 Spring AOP 是使用运行时代理实现的,所以这个对象始终是一个被代理的对象。
6.AOP 代理:由 AOP 框架创建的对象,用于实现方面契约(建议方法执行等)。在 Spring Framework 中,AOP 代理是 JDK 动态代理或 CGLIB 代理。
7.编织:将方面与其他应用程序类型或对象联系起来以创建目标对象。这可以在编译时(例如,使用 AspectJ 编译器)、加载时或运行时完成。Spring AOP 与其他纯 Java AOP 框架一样,在运行时执行编织。
AOP的通知类型:
1.置前通知:在连接点之前运行的通知,但没有能力阻止执行流继续到连接点(除非它抛出异常)。
2.置后通知:在连接点正常完成后运行的通知(例如,如果方法返回而没有抛出异常)。
3.抛出后通知:如果方法通过抛出异常退出,则执行通知。
4.After (finally) 通知:不管连接点退出的方式(正常或异常返回)都将执行的通知。
5.环绕通知:环绕连接点的通知,例如方法调用。这是最有力的建议。环绕通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续连接点还是通过返回自己的返回值或抛出异常来缩短建议的方法执行。
七、Spring JdbcTemplate类
Spring 针对数据库开发提供了 JdbcTemplate 类,该类封装了 JDBC,支持对数据库的所有操作。
使用JdbcTemplate首先要导入spring-jdbc.jar的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-jdbc.version}</version>
</dependency>
此外,Spring的事务管理还需要依赖spring-tx.jar。
接下来就是在Spring中配置JdbcTemplateBean了
<?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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
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
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!--零配置方式实现Spring Dao方式-->
<context:component-scan base-package="com.example"/>
<!--读取数据库连接配置文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--一、XML配置Spring Dao的步骤-->
<!--1.配置数据源代理对象 LazyConnectionDataSourceProxy
实现了所有目标数据源的方法
只有在执行PreparedStatement的操作时,才会去获取连接,有效提高了连接的利用率。
-->
<!--数据源配置-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<!--连接池配置-->
<constructor-arg name="targetDataSource">
<bean class="com.alibaba.druid.pool.DruidDataSource"
p:driverClassName="${db.driver}"
p:url="${db.url}"
p:username="${db.username}"
p:password="${db.password}"
p:initialSize="${db.initSize}"
p:minIdle="${db.min}"
p:maxActive="${db.max}"/>
</constructor-arg>
</bean>
<jpa:repositories base-package="com.example.dao"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource"/>
<!--2.配置JdbcTemplate-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" c:dataSource-ref="dataSource"/>
<bean class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" c:dataSource-ref="dataSource"/>
<!--事务配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
八、Spring中的事务管理
为了保证数据的完整性和一致性,出于安全考虑,我们有必要在程序中加入事务的管理。
1、使用aop织入的方式添加事务管理(用于批量管理)
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&servertimezone=UTC"/>
<property name="password" value="123456"/>
<property name="username" value="root"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
<!--在Spring容器中完成mybatis的相关配置
获得操作数据库的sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- <!–绑定mybatis的配置文件–>-->
<!-- <property name="configLocation" value="mybatis-config.xml"/>-->
<!--注册本地Mapper-->
<property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>
<!--配置别名-->
<property name="typeAliasesPackage" value="com.kuang.pojo"/>
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
</bean>
</property>
</bean>
<!--SqlSessionTemplate就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!-- <context:component-scan base-package="com.kuang.mapper"/>-->
<!-- <context:annotation-config/>-->
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<!--结合AOP实现事务的织入-->
<!--配置事务通知:-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--配置事务的传播特性:new propagation-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
<!--以上配置就是给mapper包下的所有类下的所有方法都添加了事务织入-->
</beans>
Spring中propagation的7种事务配置
Spring事务官方文档
2.使用注解式事务(用于精确管理)
在上面的配置文件中添加下面语句,开启注解式事物。
<tx:annotation-driven transaction-manager="transactionManager"/>
九、Log4J日志
日志是应用软件中不可缺少的部分,Apache 的开源项目 Log4J 是一个功能强大的日志组件。
log4j依赖
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
添加log4j.properties日志配置文件
# -----------------日志自定义配置文件(主要配置日志输出地)
# rootLogger配置日志根Logger 格式:[日志级别①],输出目的地1,输出目的地2,输出目的地3......
log4j.rootLogger=trace,forDate
# -----------------配置日志输出目的地(log4j.appender.目的地的名字)
# 目的地zktr日志会输出System.out目标的信息,格式是(日志时间%d,日志内容%m,日志换行%n)
#log4j.appender.zktr=org.apache.log4j.ConsoleAppender
#log4j.appender.zktr.Target=System.out
#log4j.appender.zktr.layout=org.apache.log4j.PatternLayout
#log4j.appender.zktr.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n
# 目的地wsl会在文件(默认在tomcat的bin目录下)中输出日志,格式是(日志时间%d,日志位置%l,日志内容%m,日志换行%n)
#log4j.appender.wsl=org.apache.log4j.FileAppender
#log4j.appender.wsl.File=logs/2000-1-1.log
#log4j.appender.wsl.layout=org.apache.log4j.PatternLayout
#log4j.appender.wsl.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n
# %l com.study.log4j.ServletAdd.doPost(ServletAdd.java:31)
### 指定固定的路径,以日期为文件名每天一个(当天默认是log.log,修改当天日期可看到会把之前的文件名进行修改logxxxx.log) ###
log4j.appender.forDate = org.apache.log4j.DailyRollingFileAppender
log4j.appender.forDate.File = logs/log.log
log4j.appender.forDate.DatePattern=yyyy-MM-dd'.log'
log4j.appender.forDate.Append = true
# 只输出DEBUG级别以上的日志!!
log4j.appender.forDate.Threshold = DEBUG
log4j.appender.forDate.layout = org.apache.log4j.PatternLayout
#log4j.appender.forDate.layout.ConversionPattern = %-d{yyyy-MM-dd} [ %t:%r ] - [ %p ] %m%n
log4j.appender.forDate.layout.ConversionPattern = %-d{yyyy-MM-dd} %p %l %m%n %n
#目的地mysql会把日志输出到数据库表mylog中。(类的全称%c,日志级别%p,日志内容%m,日志换行%n)
#log4j.appender.mysql=org.apache.log4j.jdbc.JDBCAppender
#log4j.appender.mysql.driver=com.mysql.cj.jdbc.Driver
#log4j.appender.mysql.URL=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&servertimezone=UTC
#log4j.appender.mysql.user=root
#log4j.appender.mysql.password=123456
#log4j.appender.mysql.sql=insert into mylog (create_time,info) VALUES ('%d{yyyy-MM-dd hh:mm:ss}', '%c %p %m %n')
#log4j.appender.mysql.layout=org.apache.log4j.PatternLayout
# 需要加载驱动和建表
#CREATE TABLE mylog(
#logid BIGINT PRIMARY KEY AUTO_INCREMENT,
#create_time TIMESTAMP,
#info VARCHAR(200)
#);
#输出到oracle数据库
#log4j.appender.oracle=org.apache.log4j.jdbc.JDBCAppender
#log4j.appender.oracle.driver=oracle.jdbc.driver.OracleDriver
#xe是oracle的实例名,一般是orcl
#log4j.appender.oracle.URL=jdbc:oracle:thin:@127.0.0.1:1521:xe
#log4j.appender.oracle.user=scott
#log4j.appender.oracle.password=123456
#log4j.appender.oracle.sql=insert into class_log (create_time,log) VALUES ('%d{yyyy-MM-dd hh:mm:ss}', '%c %p %m %n')
#log4j.appender.oracle.layout=org.apache.log4j.PatternLayout
# ① 日志级别,Log4j常用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG
# 通过定义的级别,可以控制到应用程序中相应级别的日志信息的开关。比如WARN级别,则低于WARN级别(INFO/DEBUG)的日志信息将不被打印出来
日志使用
public class LoggerDemo {
//1.初始日志管理器对象
static Logger logger = Logger.getLogger(LoggerDemo.class);
public static void main(String[] args) {
//2.使用默认配置(输出器=控制台 输出格式=日志界别
BasicConfigurator.configure();
//3.设置日志的输出界别
logger.setLevel(Level.ERROR);
//4.根据日志
logger.debug("调试信息...");
logger.info("基本调试信息...");
logger.warn("警告信息...");
logger.error("错误信息...");
logger.fatal("致命错误信息...");
}
}
十、Spring整合Mybatis
Mybatis在Spring中进行整合需要使用mybatis-spring依赖
Mybatis-Spring需要以下版本。
Spring整合mybatis的配置文件,完成以下配置。
- 整合了Mybatis的配置
- 添加了Mybatis的分页插件PageHelper
- 添加事务管理
- 将Mapper接口的代理实现注入到了Spring当中
<?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"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--零配置方式实现Spring Dao方式-->
<context:component-scan base-package="com.mybatis"/>
<!--读取外部配置文件
数据库连接配置
-->
<context:property-placeholder location="classpath:db.properties"/>
<!--一、XML配置Spring Dao的步骤-->
<!--1.配置数据源代理对象 LazyConnectionDataSourceProxy
实现了所有目标数据源的方法
只有在执行PreparedStatement的操作时,才会去获取连接,有效提高了连接的利用率。
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<!--连接池配置-->
<constructor-arg name="targetDataSource">
<bean class="com.alibaba.druid.pool.DruidDataSource"
p:driverClassName="${db.driver}"
p:url="${db.url}"
p:username="${db.username}"
p:password="${db.password}"
p:initialSize="${db.initSize}"
p:minIdle="${db.min}"
p:maxActive="${db.max}"/>
</constructor-arg>
</bean>
<!--2、整合Mybatis
生成sqlSessionFactory
由Spring代理生成接口的实现
-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--执行数据源对象-->
<property name="dataSource" ref="dataSource"/>
<!-- <property name="configLocation" value="classpath:mybatis-config.xml"/>-->
<property name="mapperLocations" value="classpath*:mybatis/mapper/*Mapper.xml"/>
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration"
p:logImpl="org.apache.ibatis.logging.stdout.StdOutImpl"
p:mapUnderscoreToCamelCase="true"
/>
</property>
<property name="typeAliasesPackage" value="com.mybatis.pojo"/>
<!--配置mybatis 插件-->
<property name="plugins">
<set>
<!--配置pageHelper 分页插件-->
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<!--方言:-->
<prop key="helperDialect">oracle</prop>
</props>
</property>
</bean>
</set>
</property>
</bean>
<!--将Mapper接口的代理实现注入到了Spring当中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定SqlSessionFactoryBean的名字,String类型,不要用ref-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--指定Mapper接口所在的包名-->
<property name="basePackage" value="com.mybatis.dao"/>
</bean>
<!--3.配置Spring的事务
添加事务管理器DataSourceTransactionManager
启动注解式事务
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
连接Oracle数据库配置文件
# 编写数据库连接的相关信息
db.driver=oracle.jdbc.driver.OracleDriver
db.url=jdbc:oracle:thin:@127.0.0.1:1521:xe
db.username=******
db.password=******
db.initSize=1
db.min=1
db.max=5
测试使用
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
public List<Order> selectOrderList(){
return orderMapper.selectOrderList();
}
}
@Test
public void t() {
ApplicationContext context = new ClassPathXmlApplicationContext("mybatis-spring\\mybatis-spring.xml");
OrderService orderService = context.getBean(OrderService.class);
PageInfo<Order> orderPageInfo = orderService.selectPareOrder(1, 3);
int pageNum = orderPageInfo.getPageNum();
List<Order> list = orderPageInfo.getList();
System.out.println(pageNum);
for (Order order : list) {
System.out.println(order);
}
}