其实基本核心 jar 有 beans;context;core;expression 包, 其他是依赖 log4j 日志当然 spring 的 jar 不止这些, 后期慢慢加上
3. 配置 log4j 配置文件
日志文件定义在 src 目录下
- ### direct log messages to stdout ###
- log4j.appender.stdout=org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.Target=System.err
- log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
- ### direct messages to file mylog.log ###
- log4j.appender.file=org.apache.log4j.FileAppender
- log4j.appender.file.File=c\:mylog.log
- log4j.appender.file.layout=org.apache.log4j.PatternLayout
- log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
- ### set log levels - for more verbose logging change 'info' to 'debug' ###
- log4j.rootLogger=info, stdout
4. 测试日志文件是否部署成功
- package com.clj.demo1;
- import org.apache.log4j.Logger;
- import org.junit.Test;
- /**
- * 演示日志用法
- * @author Administrator
- *
- */
- public class Demo1 {
- // 创建日志类
- private Logger log=Logger.getLogger(Demo1.class);
- @Test
- public void run1(){
- // 可以将 log4j.rootLogger 属性中的 info 改为 off 则不会再控制台显示
- log.info("执行了");
- }
- }
5. 定义一个接口和实现类
接口:
- package com.clj.demo2;
- public interface UserService {
- public void sayHello();
- }
实现类
- package com.clj.demo2;
- public class UserServiceImpl implements UserService{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public void init(){
- System.out.println("初始化");
- }
- public void sayHello() {
- System.out.println("Hello Spring"+"\t"+name);
- }
- public void destory(){
- System.out.println("销毁");
- }
- }
6. 定义 spring 专属的配置文件
定义名为 applicationContext.xml, 位置为 src 下, 与日志文件同目录, 导入相对应的约束, 并将实现类注入到配置文件中
- <?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"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
- <!-- 使用 bean 标签
- 1.id 值唯一(必写)
- 2. 注意: class 为实现类路径, 不是接口(必写)
- 3.init-method 核心方法执行之前初始化工作(选写)
- 4.destroy-method 核心方法执行之后初始化工作(选写)-->
- <bean id="userService" class="com.clj.demo2.UserServiceImpl" init-method="init" destroy-method="destory">
- <property name="name" value="佳先森"></property>
- </bean>
- </beans>
7. 测试
- public class Demo1 {
- /**
- * 原始方式
- */
- @Test
- public void run(){
- // 创建实现类
- UserServiceImpl s=new UserServiceImpl();
- s.setName("佳先森");
- s.sayHello();
- }
- /**
- * 老的工厂版本 BeanFactory
- * 旧的工厂不会创建配置文件对象
- */
- @Test
- public void run2(){
- BeanFactory factory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
- UserService us=(UserService)factory.getBean("userService");
- us.sayHello();
- }
- /**
- * 使用 spring 框架 IOC 方式
- * 新版本 factory 创建启动服务器会创建配置文件对象, 再次调用时无需加载工厂
- */
- @Test
- public void run3(){
- // 创建工厂, 加载核心配置文件(ClassPathXmlApplicationContext 从 src 下找)
- ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
- // 从工厂中获取到对象(配置文件中的 id 值, 这里用了多态)
- UserService usi=(UserService) ac.getBean("userService");
- // 调用对象的方法执行
- usi.sayHello();
- }
- /**
- * 演示 destroy-method 方法
- * bean 摧毁方法不会自动执行
- * 除非 scope= singleton 或者 web 容器中会自动调用, 但是 main 函数或测试用例需要手动调用 (需要使用 ClassPathXmlApplicationContext 的 close() 方法)
- */
- @Test
- public void run4(){
- // 创建工厂, 加载核心配置文件(ClassPathXmlApplicationContext 从 src 下找)
- ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
- // 从工厂中获取到对象(配置文件中的 id 值, 这里用了多态)
- UserService usi=(UserService) ac.getBean("userService");
- // 调用对象的方法执行
- usi.sayHello();
- //ApplicationContext 实现类提供 close 方法, 将工厂关闭就可执行 destory-method 方法
- ac.close();
- }
- }
其中旧工厂与新工厂的区别
* BeanFactory 和 ApplicationContext 的区别
* BeanFactory -- BeanFactory 采取延迟加载, 第一次 getBean 时才会初始化 Bean
* ApplicationContext -- 在加载 applicationContext.xml 时候就会创建具体的 Bean 对象的实例, 还提供了一些其他的功能
* 事件传递
* Bean 自动装配
* 各种不同应用层的 Context 实现
总结: 这是个最基本的 demo, 是将实现类配置到了 spring 配置文件中, 每次启动服务器时, 就会加载配置文件, 从而实例化了实现类
四 spring 之依赖注入
1 什么是依赖注入?
Spring 能有效地组织 J2EE 应用各层的对象不管是控制层的 Action 对象, 还是业务层的 Service 对象, 还是持久层的 DAO 对象, 都可在 Spring 的 管理下有机地协调运行 Spring 将各层的对象以松耦合的方式组织在一起, Action 对象无须关心 Service 对象的具体实现, Service 对 象无须关心持久层对象的具体实现, 各层对象的调用完全面向接口当系统需要重构时, 代码的改写量将大大减少依赖注入让 bean 与 bean 之间以配置文件组织在一起, 而不是以硬编码的方式耦合在一起理解依赖注入
依赖注入 (Dependency Injection) 和控制反转 (Inversion of Control) 是同一个概念具体含义是: 当某个角色 (可能是一个 Java 实例, 调用者) 需要另一个角色 (另一个 Java 实例, 被调用者) 的协助时, 在 传统的程序设计过程中, 通常由调用者来创建被调用者的实例但在 Spring 里, 创建被调用者的工作不再由调用者来完成, 因此称为控制反转; 创建被调用者 实例的工作通常由 Spring 容器来完成, 然后注入调用者, 因此也称为依赖注入
不管是依赖注入, 还是控制反转, 都说明 Spring 采用动态灵活的方式来管理各种对象对象与对象之间的具体实现互相透明
2. IOC 和 DI 的概念
* IOC -- Inverse of Control, 控制反转, 将对象的创建权反转给 Spring!!
* DI -- Dependency Injection, 依赖注入, 在 Spring 框架负责创建 Bean 对象时, 动态的将依赖对象注入到 Bean 组件中!!
3. 演示
对于类成员变量, 常用的注入方式有两种
属性 set 方法注入和构造方法注入
先演示第一种: 属性 set 方法注入
1)持久层
- package com.clj.demo3;
- public class CustomerDaoImpl {
- public void save(){
- System.out.println("我是持久层的 Dao");
- }
- }
2)业务层
注意: 此时是想将持久层注入到业务层, 将创建持久层实例权利交给框架, 条件是业务层必须提供持久层的成员属性和 set 方法
- package com.clj.demo3;
- /**
- * 依赖注入之将 dao 层注入到 service 层
- * @author Administrator
- *
- */
- public class CustomerServiceImpl{
- // 提供成员属相, 提供 set 方法
- private CustomerDaoImpl customerDao;
- public void setCustomerDao(CustomerDaoImpl customerDao) {
- this.customerDao = customerDao;
- }
- public void save(){
- System.out.println("我是业务层的 service...");
- //1. 原始方式
- //new CustomerDaoImpl().save();
- //2.spring 之 IOC 方式
- customerDao.save();
- }
- }
3)配置文件配置
- <!-- 演示依赖注入 -->
- <bean id="customerDao" class="com.clj.demo3.CustomerDaoImpl"/>
- <bean id="customerService" class="com.clj.demo3.CustomerServiceImpl">
- <!-- 将 Dao 注入到 service 层 -->
- <property name="customerDao" ref="customerDao"></property>
- </bean>
4)测试
- /**
- * spring 依赖注入方式
- * 将 dao 层注入到 service 层
- */
- @Test
- public void run2(){
- // 创建工厂, 加载配置文件, customerService 被创建, 从而也创建了 customerDao
- ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
- CustomerServiceImpl csi=(CustomerServiceImpl) context.getBean("customerService");
- csi.save();
- }
第二种: 构造方法注入
1)pojo 类并提供构造方法
- package com.clj.demo4;
- /**
- * 演示的构造方法的注入方式
- * @author Administrator
- *
- */
- public class Car1 {
- private String cname;
- private Double price;
- public Car1(String cname, Double price) {
- super();
- this.cname = cname;
- this.price = price;
- }
- @Override
- public String toString() {
- return "Car1 [cname=" + cname + ", price=" + price + "]";
- }
- }
2)配置文件配置
- <!-- 演示构造方法注入方式 -->
- <bean id="car1" class="com.clj.demo4.Car1">
- <!-- 写法一 < constructor-arg name="cname" value="宝马"/>
- <constructor-arg name="price" value="400000"/> -->
- <!-- 写法二 -->
- <constructor-arg index="0" value="宝马"/>
- <constructor-arg index="1" value="400000"/>
- </bean>
3)测试
- @Test
- public void run1(){
- ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
- Car1 car=(Car1) ac.getBean("car1");
- System.out.println(car);
- }
拓展: 构造方法之将一个对象注入到另一个对象中
1)pojo 类: 目的: 将上列中的车注入到人类, 使之成为其中一个属性, 则必须在此类中提供车的成员属性, 并提供有参构造方法
- package com.clj.demo4;
- public class Person {
- private String name;
- private Car1 car1;
- public Person(String name, Car1 car1) {
- super();
- this.name = name;
- this.car1 = car1;
- }
- @Override
- public String toString() {
- return "Person [name=" + name + ", car1=" + car1 + "]";
- }
- }
2)配置文件
- <!-- 构造方法之将一个对象注入到另一个对象 -->
- <bean id="person" class="com.clj.demo4.Person">
- <constructor-arg name="name" value="佳先森"/>
- <constructor-arg name="car1" ref="car1"/>
- </bean>
4. 如何注入集合数组
1)定义 pojo 类
- package com.clj.demo4;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Map;
- import java.util.Properties;
- import java.util.Set;
- /**
- * 演示集合注入的方式
- * @author Administrator
- *
- */
- public class User {
- private String[] arrs;
- private List<String> list;
- private Set<String> sets;
- private Map<String,String> map;
- private Properties pro;
- public void setPro(Properties pro) {
- this.pro = pro;
- }
- public void setSets(Set<String> sets) {
- this.sets = sets;
- }
- public void setMap(Map<String, String> map) {
- this.map = map;
- }
- public void setList(List<String> list) {
- this.list = list;
- }
- public void setArrs(String[] arrs) {
- this.arrs = arrs;
- }
- @Override
- public String toString() {
- return "User [arrs=" + Arrays.toString(arrs) + ", list=" + list
- + ", sets=" + sets + ", map=" + map + ", pro=" + pro + "]";
- }
- }
2)配置文件
- <!-- 注入集合 -->
- <bean id="user" class="com.clj.demo4.User">
- <!-- 数组 -->
- <property name="arrs">
- <list>
- <value > 数字 1</value>
- <value > 数字 2</value>
- <value > 数字 3</value>
- </list>
- </property>
- <!-- list 集合 -->
- <property name="list">
- <list>
- <value > 金在中</value>
- <value > 王杰</value>
- </list>
- </property>
- <!-- set 集合 -->
- <property name="sets">
- <set>
- <value > 哈哈</value>
- <value > 呵呵</value>
- </set>
- </property>
- <!-- map 集合 -->
- <property name="map">
- <map>
- <entry key="aa" value="rainbow"/>
- <entry key="bb" value="hellowvenus"/>
- </map>
- </property>
- <!-- 属性文件 -->
- <property name="pro">
- <props>
- <prop key="username">root</prop>
- <prop key="password">123</prop>
- </props>
- </property>
- </bean>
3)测试
- /**
- * 测试注入集合
- */
- @Test
- public void run3(){
- ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
- User user= (User) ac.getBean("user");
- System.out.println(user);
- }
5. 怎么分模块开发
在主配置文件加入 < import > 标签(假如此时在 com.clj.test 包下定义了一个配置文件 applicationContext2.xml)
- <!-- 分模块开发之引入其他配置文件 -->
- <import resource="com/clj/test/applicationContext2.xml"/>
五详解 Spring 框架的 IOC 之注解方式
1 入门
1). 导入 jar 包
除了先前 6 个包, 玩注解还需一个 spring-aop 包
2). 持久层和实现层(这里忽略接口)
持久层
- package com.clj.demo1;
- import org.springframework.context.annotation.Scope;
- import org.springframework.stereotype.Component;
- import org.springframework.stereotype.Repository;
- /**
- * UserDaoImpl 交给 IOC 的容器管理
- * @author Administrator
- *
- */
- public class UserDaoImpl implements UserDao{
- @Override
- public void save() {
- System.out.println("保存客户");
- }
- }
业务层
- package com.clj.demo1;
- import javax.annotation.PostConstruct;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Component;
- public class UserServiceImpl implements UserService{
- @Override
- public void sayHello() {
- System.out.println("Hello spring"+name);
- }
- }
3). 定义配置文件
此时约束条件需添加 context 约束, 并添加组件扫描
- <?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"> <!-- bean definitions here -->
- <!-- 开启注解扫面 :base-package 指定扫面对 包 -->
- <context:component-scan base-package="com.clj.demo1"/>
- </beans>
4)在实现类中添加注解
- /**
- * 组件注解, 可以用来标记当前的类
- * 类似 < bean id="userService" class="com.clj.demo1.UserServiceImpl">
- * value 表示给该类起个别名
- */
- @Component(value="userService")
- public class UserServiceImpl implements UserService{
- // 省略
- }
5)编写测试
- /**
- * 注解方式
- */
- @Test
- public void run2(){
- ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
- UserService us=(UserService) ac.getBean("userService");
- us.sayHello();
- }
2. 关于 bean 管理常用属性
1. @Component: 组件.(作用在类上) 最原始的注解, 所有需要注解的类都写这个没问题, 他是通用的
2. Spring 中提供 @Component 的三个衍生注解:(功能目前来讲是一致的)
* @Controller -- 作用在 WEB 层
* @Service -- 作用在业务层
* @Repository -- 作用在持久层
* 说明: 这三个注解是为了让标注类本身的用途清晰, Spring 在后续版本会对其增强
3. 属性注入的注解(说明: 使用注解注入的方式, 可以不用提供 set 方法)
* 如果是注入的普通类型, 可以使用 value 注解
* @Value -- 用于注入普通类型
* 如果注入的是对象类型, 使用如下注解
* @Autowired -- 默认按类型进行自动装配 匹配的是类型, 与注入类的类名无关
* 如果想按名称注入
* @Qualifier -- 强制使用名称注入 必须与 Autowired 一起用, 指定类名, 与注入的类名有关
* @Resource -- 相当于 @Autowired 和 @Qualifier 一起使用
* 强调: Java 提供的注解
* 属性使用 name 属性
4. Bean 的作用范围注解
* 注解为 @Scope(value="prototype"), 作用在类上值如下:
* singleton -- 单例, 默认值
* prototype -- 多例
5. Bean 的生命周期的配置(了解)
* 注解如下:
* @PostConstruct -- 相当于 init-method
* @PreDestroy -- 相当于 destroy-method
1. 演示属性对象注解
条件: 采用扫描的方式将属性 (name) 和对象 (userDaoImpl) 注入到业务层中
1)持久层开启注解扫描 Repository
- //@Component(value="userDao")通用类注解
- @Repository(value="ud")
- public class UserDaoImpl implements UserDao{
- @Override
- public void save() {
- System.out.println("保存客户");
- }
- }
2)业务层针对属性和对象提供注解
- package com.clj.demo1;
- import javax.annotation.PostConstruct;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Component;
- /**
- * 组件注解, 可以用来标记当前的类
- * 类似 < bean id="userService" class="com.clj.demo1.UserServiceImpl">
- * value 表示给该类起个别名
- *$/@Scope(value="grototype")多列的(singletype 为单列)
- @Component(value="userService")
- public class UserServiceImpl implements UserService{
- // 属性注解: 相当于给 name 属性注入指定的字符串, setName 方法可以省略不写
- @Value(value="佳先森")
- private String name;
- /**
- * 引用注入方式一: Autowired()
- * 引用注入方式二: Autowired()+Qualifier
- * 引用注入方式三:@Resource(name="userDao") java 方式, 按名称识别注入
- *$/Autowired()按类型自动装配注入(缺点: 因为是按类型匹配, 所以不是很准确)
- @Autowired()
- @Qualifier(value="ud") // 按名称注入, 得与 Autowired 一起用, 两者一起能指定类
- private UserDao userDao;
- // 注意 Qualifier 中的 value 是指定 UserDaoImpl 类名顶上的注解名, 也可以指定配置文件中 bean 的 id 名
- /*public void setName(String name) {
- this.name = name;
- }*/
- @Override
- public void sayHello() {
- System.out.println("Hello spring"+name);
- userDao.save();
- }
- //@PostConstruct 标签用于 action 生命周期中初始化的注解
- @PostConstruct
- public void init(){
- System.out.println("初始化...");
- }
- }
注意: 至于集合还是推荐使用配置文件方式
2.Spring 框架整合 JUnit 单元测试
1)添加单元测试所需依赖包 spring-test.jar
注意: 基于 myeclipes 自带 Junit 环境, 但是有时因为版本问题, 可能需要比较新的 Junit 环境, 这里我在网上下了一个教新的 Junit-4.9 的 jar 包, 如果 myeclipes 较新的话无须考虑
2)编写测试类, 添加相对应的注解
@RunWith 与 @ContextConfiguration(此是用于加载配置文件, 因为默认从 WebRoot 路径为一级目录, 加上此是认定 src 为一级目录)
- package com.clj.demo2;
- import javax.annotation.Resource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- import com.clj.demo1.UserService;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext.xml")
- public class Demo2 {
- @Resource(name="userService")
- private UserService userService;
- @Test
- public void run1(){
- userService.sayHello();
- }
- }
六. spring 框架之 AOP
1. 什么是 AOP
* 在软件业, AOP 为 Aspect Oriented Programming 的缩写, 意为: 面向切面编程, 功能模块化
* AOP 是一种编程范式, 隶属于软工范畴, 指导开发者如何组织程序结构
* AOP 最早由 AOP 联盟的组织提出的, 制定了一套规范. Spring 将 AOP 思想引入到框架中, 必须遵守 AOP 联盟的规范
* 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
* AOP 是 OOP 的延续, 是软件开发中的一个热点, 也是 Spring 框架中的一个重要内容, 是函数式编程的一种衍生范型
* 利用 AOP 可以对业务逻辑的各个部分进行隔离, 从而使得业务逻辑各部分之间的耦合度降低, 提高程序的可重用性, 同时提高了开发的效率
AOP 采取横向抽取机制, 取代了传统纵向继承体系重复性代码(性能监视事务管理安全检查缓存)
2. 为什么要学习 AOP
* 可以在不修改源代码的前提下, 对程序进行增强!!(为固定的方法生成一个代理, 在访问该方法之前, 先进入代理, 在代理中, 可以编写更多的功能, 使之方法的功能更强, 使得程序进行增 强)
Aop: 面向切面编程, 将一切事模块化, 每个模块比较独立, 模块可以共用(相同的), 不同的格外自定义用此替代传统的面向纵向编程, 提高程序的可重用性
3.AOP 的实现(实现原理)
Aop 的实现包含两种代理方式 < 1 > 实现类接口: 采用 JDK 动态代理 < 2 > 未实现类接口: 采用 CGLIB 动态代理
1. 实现 JDK 动态代理
1)定义持久层接口实现类
- package com.clj.demo3;
- public interface UserDao {
- public void save();
- public void update();
- }
- package com.clj.demo3;
- public class UserDaoImpl implements UserDao {
- @Override
- public void save() {
- System.out.println("保存用户");
- }
- @Override
- public void update() {
- System.out.println("修改用户");
- }
- }
2)定义 JDK 动态代理工具类
此工具类是在执行持久层 save 方法时增加一些功能, 在开发中做到在不更改源码情况下增强某方法
- package com.clj.demo3;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /**
- * 使用 JDK 的方式生成代理对象(演示 AOP 原理)
- * @author Administrator
- *
- */
- public class MyProxyUtils {
- public static UserDao getProxy(final UserDao dao){
- // 使用 Proxy 类生成代理对象
- UserDao proxy=(UserDao)Proxy.newProxyInstance(dao.getClass().getClassLoader() , dao.getClass().getInterfaces(),new InvocationHandler() {
- // 只要代理对象一执行, invoke 方法就会执行一次
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- //proxy 代表当前代理对象
- //method 当前对象执行的方法
- //args 封装的参数
- // 让到类的 save 或者 update 方法正常执行下去
- if("save".equals(method.getName())){
- System.out.println("执行了保存");
- // 开启事务
- }
- return method.invoke(dao, args);
- }
- });
- return proxy;
- }
- }
3)测试
- package com.clj.demo3;
- import org.junit.Test;
- public class Demo1 {
- @Test
- public void run1(){
- // 获取目标对象
- UserDao dao=new UserDaoImpl();
- dao.save();
- dao.update();
- System.out.println("===============");
- // 使用工具类, 获取到代理对象
- UserDao proxy=MyProxyUtils.getProxy(dao);
- // 调用代理对象的方法
- proxy.save();
- proxy.update();
- }
- }
2. 实现 CGLIB 技术
1)定义持久层, 此时没有接口
- package com.clj.demo4;
- public class BookDaoImpl {
- public void save(){
- System.out.println("保存图书");
- }
- public void update(){
- System.out.println("修改图书");
- }
- }
2)编写工具类
- package com.clj.demo4;
- import java.lang.reflect.Method;
- import org.springframework.cglib.proxy.Enhancer;
- import org.springframework.cglib.proxy.MethodInterceptor;
- import org.springframework.cglib.proxy.MethodProxy;
- /**
- * Cglib 代理方式实现原理
- * @author Administrator
- *
- */
- public class MyCglibUtils {
- /**
- * 使用 CGLIB 方式生成代理对象
- * @return
- */
- public static BookDaoImpl getProxy(){
- Enhancer enhancer=new Enhancer();
- // 设置父类
- enhancer.setSuperclass(BookDaoImpl.class);
- // 设置回调函数
- enhancer.setCallback(new MethodInterceptor() {
- @Override
- public Object intercept(Object obj, Method method, Object[] objs,
- MethodProxy methodProxy) throws Throwable {
- if(method.getName().equals("save")){
- System.out.println("我保存了");
- System.out.println("代理对象执行了");
- }
- return methodProxy.invokeSuper(obj, objs);// 是方法执行下去
- }
- });
- // 生成代理对象
- BookDaoImpl proxy=(BookDaoImpl) enhancer.create();
- return proxy;
- }
- }
3)编写测试类
- package com.clj.demo4;
- import org.junit.Test;
- public class Demo1 {
- @Test
- public void run1(){
- // 目标对象
- BookDaoImpl dao=new BookDaoImpl();
- dao.save();
- dao.update();
- System.out.println("==========");
- BookDaoImpl proxy=MyCglibUtils.getProxy();
- proxy.save();
- proxy.update();
- }
- }
3Spring 基于 AspectJ 的 AOP 的开发(配置文件方式)
1)部署环境, 导入相对应的 jar 包
2)创建配置文件, 并引入 AOP 约束
- <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">
3)创建接口和实现类
- package com.clj.demo5;
- public interface CustomerDao {
- public void save();
- public void update();
- }
- package com.clj.demo5;
- /**
- * 采用配置文件的方式 诠释 AOP
- * @author Administrator
- *
- */
- public class CustomerDaoImpl implements CustomerDao {
- @Override
- public void save() {
- // 模拟异常
- //int a=10/0;
- System.out.println("保存客户了啊");
- }
- @Override
- public void update() {
- // TODO Auto-generated method stub
- System.out.println("更新客户了啊");
- }
- }
4)定义切面类
- package com.clj.demo5;
- import org.aspectj.lang.ProceedingJoinPoint;
- /**
- * 切面类: 切入点 + 通知
- * @author Administrator
- *
- */
- public class MyAspectXml {
- /**
- * 通知(具体的增强)
- */
- public void log(){
- System.out.println("记录日志");
- }
- /**
- * 方法执行成功或者异常都会执行
- */
- public void after(){
- System.out.println("最终通知");
- }
- /**
- * 方法执行之后, 执行后置通知, 如果程序出现异常, 后置通知不会执行
- */
- public void afterReturn(){
- System.out.println("后置通知");
- }
- /**
- * 方法执行之后, 如果程序有异常, 才会执行异常通知
- */
- public void afterThrowing(){
- System.out.println("异常通知");
- }
- /**
- * 环绕通知: 方法执行之前和方法执行之后进行通知,
- * 默认情况下, 目标对象的方法不能执行的, 需要手动让目标对象执行
- */
- public void around(ProceedingJoinPoint joinPoint){
- System.out.println("环绕通知 1");
- // 手动让目标对象的方法执行
- try {
- joinPoint.proceed();
- } catch (Throwable e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("环绕通知 2");
- }
- }
5)注入实现类和切面类
- <?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 definitions here -->
- <!-- 配置客户的 dao -->
- <bean id="customerDao" class="com.clj.demo5.CustomerDaoImpl"/>
- <!-- 编写切面类配置好 -->
- <bean id="myAspectXml" class="com.clj.demo5.MyAspectXml"/>
- <!-- 配置 AOP -->
- <aop:config>
- <!-- 配置切面类: 切入点 + 通知 (类型)-->
- <aop:aspect ref="myAspectXml">
- <!-- 配置前置通知, save 方法执行之前, 增强方法会执行 -->
- <!-- 切入点表达式: execution(public void com.clj.demo5.CustomerDaoImpl.save()) -->
- <!-- 切入点表达式:
- 1.execution()固定的, 必写
- 2.public 可以省略不写
- 3. 返回值 必写, 严格根据切入点方法而定, 否则增强方法不会执行, 可以用 * 代替, 表示任意的返回值
- 4. 包名 必写, 可以用 * 代替(如:*..*(默认所有包); com.clj.*)
- 5. 类名 必写, 可以部分用 *(如 * DaoImpl 表示以'DaoImpl'结尾的持久层实现类), 但不建议用 * 代替整个类名
- 6. 方法 必写, 可以部分用 *(如 save * 表示以'save'开头的方法), 但不建议用 * 代替整个类名
- 7. 方法参数 根据实际方法而定, 可以用'..'表示有 0 或者多个参数
- -->
- <!-- <aop:before method="log" pointcut="execution(public void com.clj.*.CustomerDaoImpl.save(..))"/> -->
- <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>
- </aop:aspect>
- </aop:config>
- </beans>
6)测试
- package com.clj.demo5;
- import javax.annotation.Resource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext.xml")
- public class Demo1 {
- @Resource(name="customerDao")
- private CustomerDao customerDao;
- @Test
- public void run(){
- customerDao.save();
- customerDao.update();
- }
- }
扩展: 切面类升级
- <?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 definitions here -->
- <bean id="myAspectXml" class="com.clj.demo5.MyAspectXml"/>
- <aop:config>
- <aop:aspect ref="myAspectXml">
- <!-- 配置最终通知
- <aop:after method="after" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->
- <!-- 配置后置通知
- <aop:after-returning method="afterReturn" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->
- <!-- 配置异常通知
- <aop:after-throwing method="afterThrowing" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->
- <aop:around method="around" pointcut="execution(* *..*.*DaoImpl.update*(..))"/>
- </aop:aspect>
- </aop:config>
- </beans>
4Spring 框架 AOP 之注解方式
1)创建接口和实现类
- package com.clj.demo1;
- public interface CustomerDao {
- public void save();
- public void update();
- }
- package com.clj.demo1;
- public class CustomerDaoImpl implements CustomerDao{
- @Override
- public void save() {
- // TODO Auto-generated method stub
- System.out.println("保存客户..");
- }
- @Override
- public void update() {
- // TODO Auto-generated method stub
- System.out.println("更新客户");
- }
- }
2)定义切面类
- package com.clj.demo1;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- /**
- * 注解方式的切面类
- * @Aspect 表示定义为切面类
- */
- @Aspect
- public class MyAspectAnno {
- // 通知类型:@Before 前置通知(切入点的表达式)
- @Before(value="execution(public * com.clj.demo1.CustomerDaoImpl.save())")
- public void log(){
- System.out.println("记录日志");
- }
- // 引入切入点
- @After(value="MyAspectAnno.fun()")
- public void after(){
- System.out.println("执行之后");
- }
- @Around(value="MyAspectAnno.fun()")
- public void around(ProceedingJoinPoint joinPoint){
- System.out.println("环绕通知 1");
- try {
- // 让目标对象执行
- joinPoint.proceed();
- } catch (Throwable e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("环绕通知 2");
- }
- // 自定义切入点
- @Pointcut(value="execution(public * com.clj.demo1.CustomerDaoImpl.save())")
- public void fun(){
- }
- }
3)配置切面类和实现类, 并开启自动代理
- <?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:aop="http://www.springframework.org/schema/aop"
- 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/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd">
- <!-- 开启自动注解代理 -->
- <aop:aspectj-autoproxy/>
- <!-- 配置目标对象 -->
- <bean id="customerDao" class="com.clj.demo1.CustomerDaoImpl"/>
- <!-- 配置切面类 -->
- <bean id="myAspectAnno" class="com.clj.demo1.MyAspectAnno"/>
- </beans>
七 Spring 之 JDBC
spring 提供了 JDBC 模板: JdbcTemplate 类
1. 快速搭建
1)部署环境
这里在原有的 jar 包基础上, 还要添加关乎 jdbc 的 jar 包, 这里使用的是 mysql 驱动
2)配置内置连接池, 将连接数据库程序交给框架管理, 并配置 Jdbc 模板类
- <?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:aop="http://www.springframework.org/schema/aop"
- 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/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd">
- <!-- 先配置连接池(内置) -->
- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
- <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
- <property name="url" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="username" value="root"/>
- <property name="password" value="root"/>
- </bean>
- <!-- 配置 JDBC 的模板类 -->
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- </beans>
3)测试
- package com.clj.demo2;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.List;
- import javax.annotation.Resource;
- import org.apache.commons.dbcp.BasicDataSource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.cglib.beans.BeanMap;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.jdbc.core.RowMapper;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- /**
- * 测试 JDBC 的模板类, 使用 IOC 的方式
- * @author Administrator
- *
- */
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext.xml")
- public class Demo2 {
- @Resource(name="jdbcTemplate")
- private JdbcTemplate jdbcTemplate;
- /**
- * 插入
- */
- @Test
- public void run1(){
- String sql="insert into t_account values(null,?,?)";
- jdbcTemplate.update(sql,"李钇林",10000);
- }
- /**
- * 更新
- */
- @Test
- public void run2(){
- String sql="update t_account set name=? where id=?";
- jdbcTemplate.update(sql,"李钇林",1);
- }
- /**
- * 删除
- */
- @Test
- public void run3(){
- String sql="delete from t_account where id=?";
- jdbcTemplate.update(sql,4);
- }
- /**
- * 测试查询, 通过主键来查询一条记录
- */
- @Test
- public void run4(){
- String sql="select * from t_account where id=?";
- Account ac=jdbcTemplate.queryForObject(sql, new BeanMapper(),1);
- System.out.println(ac);
- }
- /**
- * 查询所有
- */
- @Test
- public void run5(){
- String sql="select * from t_account";
- List<Account> ac=jdbcTemplate.query(sql,new BeanMapper());
- System.out.println(ac);
- }
- }
- /**
- * 定义内部类(手动封装数据(一行一行封装数据, 用于查询所有)
- * @author Administrator
- *
- */
- class BeanMapper implements RowMapper<Account>{
- @Override
- public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
- Account ac=new Account();
- ac.setId(rs.getInt("id"));
- ac.setName(rs.getString("name"));
- ac.setMoney(rs.getDouble("money"));
- return ac;
- }
- }
2 配置开源连接池
一般现在企业都是用一些主流的连接池, 如 c3p0 和 dbcp
首先配置 dbcp
1)导入 dbcp 依赖 jar 包
2)编写配置文件
- <!-- 配置 DBCP 开源连接池 -->
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
- <property name="url" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="username" value="root"/>
- <property name="password" value="root"/>
- </bean>
将模板类中引入的内置类 datasource 改为开源连接池的
3)编写测试类
配置 c3p0
1)导入 c3p0 依赖 jar 包
2)配置 c3p0
- <!-- 配置 C3P0 开源连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver"/>
- <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="user" value="root"/>
- <property name="password" value="root"/>
- </bean>
将模板类中引入的内置类 datasource 改为开源连接池的
3)编写测试类
八 Spring 之事务
1 什么是事务
数据库事务 https://baike.baidu.com/item/数据库事务 (Database Transaction) , 是指作为单个逻辑工作单元执行的一系列操作 https://baike.baidu.com/item/操作/33052 , 要么完全地执行, 要么完全地不执行 事务处理可以确保除非事务性单元内的所有操作都成功完成, 否则不会永久更新面向数据的资源通过将一组相关操作组合为一个要么全部成功要么全部失败的单元, 可以简化错误恢复并使应用程序更加可靠一个逻辑工作单元要成为事务, 必须满足所谓的 ACID(原子性一致性隔离性和持久性)属性事务是数据库运行中的逻辑工作单位, 由 DBMS 中的事务管理子系统负责事务的处理
----- 百度百科
2 怎么解决事务安全性问题
读问题解决, 设置数据库隔离级别; 写问题解决可以使用 悲观锁和乐观锁的方式解决
3 快速开发
方式一: 调用模板类, 将模板注入持久层
1)编写相对应的持久层和也外层, 这里省略接口
- package com.clj.demo3;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.jdbc.core.support.JdbcDaoSupport;
- public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
- // 方式一: 将 jdbc 模板类注入到配置文件中, 直接在持久层写模板类
- private JdbcTemplate jdbcTemplate;
- public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
- public void outMoney(String out, double money) {
- String sql="update t_account set money=money-? where name=?";
- jdbcTemplate().update(sql,money,out);
- }
- public void inMoney(String in, double money) {
- String sql="update t_account set money=money+? where name=?";
- jdbcTemplate().update(sql,money,in);
- }
- }
- package com.clj.demo4;
- import org.springframework.transaction.TransactionStatus;
- import org.springframework.transaction.support.TransactionCallbackWithoutResult;
- import org.springframework.transaction.support.TransactionTemplate;
- public class AccountServiceImpl implements AccountService{
- // 采用的是配置文件注入方式, 必须提供 set 方法
- private AccountDao accountDao;
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
- @Override
- public void pay(String out, String in, double money) {
- // TODO Auto-generated method stub
- accountDao.outMoney(out, money);
- int a=10/0;
- accountDao.inMoney(in, money);
- }
- }
2)配置相对应的配置文件
- <?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:aop="http://www.springframework.org/schema/aop"
- 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/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd">
- <!-- 配置 C3P0 开源连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver"/>
- <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="user" value="root"/>
- <property name="password" value="root"/>
- </bean>
- <!-- 配置 JDBC 的模板类 -->
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <!-- 配置业务层和持久层 -->
- <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">
- <property name="accountDao" ref="accountDao"/>
- </bean>
- <bean id="accountDao" class="com.clj.demo3.AccountDaoImpl">
- <!-- 注入模板类 -->
- <property name="jdbcTemplate" ref="jdbcTemplate"/>
- <property name="dataSource" ref="dataSource"/>
- </bean>
- </beans>
3)测试类
- package com.clj.demo3;
- import javax.annotation.Resource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext.xml")
- public class Demo1 {
- @Resource(name="accountService")
- private AccountService accountService;
- @Test
- public void Demo1(){
- // 调用支付的方法
- accountService.pay("佳先森","李钇林",100);
- }
- }
方式二: 持久层继承 JdbcDaoSupport 接口, 此接口封装了模板类 jdbcTemplate
1)编写配置文件
- <?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:aop="http://www.springframework.org/schema/aop"
- 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/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd">
- <!-- 配置 C3P0 开源连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver"/>
- <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="user" value="root"/>
- <property name="password" value="root"/>
- </bean>
- <!-- 配置业务层和持久层 -->
- <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">
- <property name="accountDao" ref="accountDao"/>
- </bean>
- <bean id="accountDao" class="com.clj.demo3.AccountDaoImpl">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- </beans>
2)更改持久层
- package com.clj.demo3;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.jdbc.core.support.JdbcDaoSupport;
- public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
- // 方式一: 将 jdbc 模板类注入到配置文件中, 直接在持久层写模板类
- // private JdbcTemplate jdbcTemplate;
- // public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
- // this.jdbcTemplate = jdbcTemplate;
- // }
- // 方式二: 持久层继承 JdbcDaoSupport, 它里面封转了模板类, 配置文件持久层无需注入模板类, 也不需要配置模板类
- public void outMoney(String out, double money) {
- //jdbcTemplate.update(psc);
- String sql="update t_account set money=money-? where name=?";
- this.getJdbcTemplate().update(sql,money,out);
- }
- public void inMoney(String in, double money) {
- String sql="update t_account set money=money+? where name=?";
- this.getJdbcTemplate().update(sql,money,in);
- }
- }
3)更改业务层
- package com.clj.demo4;
- import org.springframework.transaction.TransactionStatus;
- import org.springframework.transaction.support.TransactionCallbackWithoutResult;
- import org.springframework.transaction.support.TransactionTemplate;
- public class AccountServiceImpl implements AccountService{
- // 采用的是配置文件注入方式, 必须提供 set 方法
- private AccountDao accountDao;
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
- @Override
- public void pay(String out, String in, double money) {
- // TODO Auto-generated method stub
- accountDao.outMoney(out, money);
- int a=10/0;
- accountDao.inMoney(in, money);
- }
- }
4)测试类和上述一样
4spring 事务管理
Spring 为了简化事务管理的代码: 提供了模板类 TransactionTemplate, 所以手动编程的方式来管理事务, 只需要使用该模板类即可!!
九 Spring 框架的事务管理之编程式的事务管理
1 手动编程方式
1)快速部署, 搭建配置文件, 配置事务管理和事务管理模板, 并在持久层注入事务管理模板
- <?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:aop="http://www.springframework.org/schema/aop"
- 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/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd">
- <!-- 配置 C3P0 开源连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver"/>
- <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="user" value="root"/>
- <property name="password" value="root"/>
- </bean>
- <!-- 配置业务层和持久层 -->
- <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">
- <property name="accountDao" ref="accountDao"/>
- <property name="transactionTemplate" ref="transactionTemplate"/>
- </bean>
- <bean id="accountDao" class="com.clj.demo3.AccountDaoImpl">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <!-- 配置平台事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <!-- 手动编码方式, 提供了模板类, 使用该类管理事务比较简单 -->
- <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
- <property name="transactionManager" ref="transactionManager"/>
- </bean>
- </beans>
2)在业务层使用模板事务管理
- package com.clj.demo3;
- import org.springframework.transaction.TransactionStatus;
- import org.springframework.transaction.support.TransactionCallbackWithoutResult;
- import org.springframework.transaction.support.TransactionTemplate;
- public class AccountServiceImpl implements AccountService{
- // 采用的是配置文件注入方式, 必须提供 set 方法
- private AccountDao accountDao;
- // 注入事务模板类
- private TransactionTemplate transactionTemplate;
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
- public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
- this.transactionTemplate = transactionTemplate;
- }
- /**
- * 转账的方法
- */
- public void pay(final String out,final String in, final double money) {
- transactionTemplate.execute(new TransactionCallbackWithoutResult() {
- // 事务的执行, 如果没有问题, 提交, 如果楚翔异常, 回滚
- protected void doInTransactionWithoutResult(TransactionStatus arg0) {
- // TODO Auto-generated method stub
- accountDao.outMoney(out, money);
- int a=10/0;
- accountDao.inMoney(in, money);
- }
- });
- }
- }
3)测试类和上一致
- package com.clj.demo4;
- import javax.annotation.Resource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext2.xml")
- public class Demo2 {
- @Resource(name="accountService")
- private AccountService accountService;
- @Test
- public void Demo1(){
- // 调用支付的方法
- accountService.pay("佳先森","李钇林",100);
- }
- }
十 Spring 框架的事务管理之声明式事务管理, 即通过配置文件来完成事务管理(AOP 思想)
申明式事务有两种方式: 基于 AspectJ 的 XML 方式; 基于 AspectJ 的注解方式
1XML 方式
1)配置配置文件
需要配置平台事务管理
- <!-- 配置 C3P0 开源连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver" />
- <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"
- />
- <property name="user" value="root" />
- <property name="password" value="root" />
- </bean>
- <!-- 配置平台事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
配置事务增强
- <tx:advice id="myAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <!-- 给方法设置数据库属性(隔离级别, 传播行为) -->
- <!--propagation 事务隔离级别: 一般采用默认形式: tx:method 可以设置多个 -->
- <tx:method name="pay" propagation="REQUIRED"/>
- </tx:attributes>
- </tx:advice>
aop 切面类
- <aop:config>
- <!-- aop:advisor, 是 spring 框架提供的通知 -->
- <aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.clj.demo4.AccountServiceImpl.pay(..))"/>
- </aop:config>
全部代码
- <?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:aop="http://www.springframework.org/schema/aop"
- 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/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd">
- <!-- 配置 C3P0 开源连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver"/>
- <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="user" value="root"/>
- <property name="password" value="root"/>
- </bean>
- <!-- 配置平台事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <!-- 申明式事务(采用 XML 文件的方式) -->
- <!-- 先配置通知 -->
- <tx:advice id="myAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <!-- 给方法设置数据库属性(隔离级别, 传播行为) -->
- <!--propagation 事务隔离级别: 一般采用默认形式: tx:method 可以设置多个 -->
- <tx:method name="pay" propagation="REQUIRED"/>
- </tx:attributes>
- </tx:advice>
- <!-- 配置 AOP: 如果是自己编写的 AOP, 使用 aop:aspect 配置, 使用的是 Spring 框架提供的通知 -->
- <aop:config>
- <!-- aop:advisor, 是 spring 框架提供的通知 -->
- <aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.clj.demo4.AccountServiceImpl.pay(..))"/>
- </aop:config>
- <!-- 配置业务层和持久层 -->
- <bean id="accountService" class="com.clj.demo4.AccountServiceImpl">
- <property name="accountDao" ref="accountDao"/>
- </bean>
- <bean id="accountDao" class="com.clj.demo4.AccountDaoImpl">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- </beans>
2)编写持久层和业务层(省略接口)
- package com.clj.demo5;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.jdbc.core.support.JdbcDaoSupport;
- public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
- // 方式一: 将 jdbc 模板类注入到配置文件中, 直接在持久层写模板类
- // private JdbcTemplate jdbcTemplate;
- // public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
- // this.jdbcTemplate = jdbcTemplate;
- // }
- // 方式二: 持久层继承 JdbcDaoSupport, 它里面封转了模板类, 配置文件持久层无需注入模板类, 也不需要配置模板类
- public void outMoney(String out, double money) {
- //jdbcTemplate.update(psc);
- String sql="update t_account set money=money-? where name=?";
- this.getJdbcTemplate().update(sql,money,out);
- }
- public void inMoney(String in, double money) {
- String sql="update t_account set money=money+? where name=?";
- this.getJdbcTemplate().update(sql,money,in);
- }
- }
- package com.clj.demo5;
- import org.springframework.transaction.TransactionStatus;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.transaction.support.TransactionCallbackWithoutResult;
- import org.springframework.transaction.support.TransactionTemplate;public class AccountServiceImpl implements AccountService{
- // 采用的是配置文件注入方式, 必须提供 set 方法
- private AccountDao accountDao;
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
- @Override
- public void pay(String out, String in, double money) {
- // TODO Auto-generated method stub
- accountDao.outMoney(out, money);
- int a=10/0;
- accountDao.inMoney(in, money);
- }
- }
3)测试类
- package com.clj.demo4;
- import javax.annotation.Resource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext2.xml")
- public class Demo2 {
- @Resource(name="accountService")
- private AccountService accountService;
- @Test
- public void Demo1(){
- // 调用支付的方法
- accountService.pay("佳先森","李钇林",100);
- }
- }
2 注解方式
1)配置配置文件
配置事务管理
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver"/>
- <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="user" value="root"/>
- <property name="password" value="root"/>
- </bean>
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
开启注释事务
- <!-- 开启事务的注解 -->
- <tx:annotation-driven transaction-manager="transactionManager"/>
全部代码
- <?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:aop="http://www.springframework.org/schema/aop"
- 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/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd">
- <!-- 配置 C3P0 开源连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="com.mysql.jdbc.Driver"/>
- <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
- <property name="user" value="root"/>
- <property name="password" value="root"/>
- </bean>
- <!-- 配置平台事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <!-- 开启事务的注解 -->
- <tx:annotation-driven transaction-manager="transactionManager"/>
- <!-- 配置业务层和持久层 -->
- <bean id="accountService" class="com.clj.demo5.AccountServiceImpl">
- <property name="accountDao" ref="accountDao"/>
- </bean>
- <bean id="accountDao" class="com.clj.demo5.AccountDaoImpl">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- </beans>
2)业务层增加 @Transactional
- package com.clj.demo5;
- import org.springframework.transaction.TransactionStatus;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.transaction.support.TransactionCallbackWithoutResult;
- import org.springframework.transaction.support.TransactionTemplate;
- // 在当前类加此注解表示当前类所有的全部都有事务
- @Transactional
- public class AccountServiceImpl implements AccountService{
- // 采用的是配置文件注入方式, 必须提供 set 方法
- private AccountDao accountDao;
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
- @Override
- public void pay(String out, String in, double money) {
- // TODO Auto-generated method stub
- accountDao.outMoney(out, money);
- int a=10/0;
- accountDao.inMoney(in, money);
- }
- }
3)持久层不变
- package com.clj.demo5;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.jdbc.core.support.JdbcDaoSupport;
- public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
- // 方式一: 将 jdbc 模板类注入到配置文件中, 直接在持久层写模板类
- // private JdbcTemplate jdbcTemplate;
- // public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
- // this.jdbcTemplate = jdbcTemplate;
- // }
- // 方式二: 持久层继承 JdbcDaoSupport, 它里面封转了模板类, 配置文件持久层无需注入模板类, 也不需要配置模板类
- public void outMoney(String out, double money) {
- //jdbcTemplate.update(psc);
- String sql="update t_account set money=money-? where name=?";
- this.getJdbcTemplate().update(sql,money,out);
- }
- public void inMoney(String in, double money) {
- String sql="update t_account set money=money+? where name=?";
- this.getJdbcTemplate().update(sql,money,in);
- }
- }
4)测试类
- package com.clj.demo5;
- import javax.annotation.Resource;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext3.xml")
- public class Demo3 {
- @Resource(name="accountService")
- private AccountService accountService;
- @Test
- public void Demo1(){
- // 调用支付的方法
- accountService.pay("佳先森","李钇林",100);
- }
- }
来源: https://www.cnblogs.com/cailijia52o/p/8699845.html