1.代码存在的问题
2.引出代理模式
3.静态代理
4.动态代理
5.AOP的思想和概念
6.pointcut语法
7.aop的xml配置
8.不同时机的增强
9.获取增强的参数
10.aop的注解配置
一、代码存在的问题
案例:每一个业务方法都要处理事务.
1、pom.xml参考前面,有的依赖是多余的。添加了lombok
<?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.xj</groupId>
<artifactId>Spring03</artifactId>
<version>1.0.0</version>
<properties>
<!--定义全局变量,变量名为:project.spring.version-->
<project.spring.version>5.0.0.RELEASE</project.spring.version>
</properties>
<dependencies>
<!--Spring-core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${project.spring.version}</version>
</dependency>
<!--Spring-beans-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${project.spring.version}</version>
</dependency>
<!--Spring-test-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${project.spring.version}</version>
</dependency>
<!--Spring-expression-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${project.spring.version}</version>
</dependency>
<!--Spring-context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${project.spring.version}</version>
</dependency>
<!--Spring-aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${project.spring.version}</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>
<build>
<!--从哪个地方加载配置文件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
2、事务管理器TransactionManager
package com.xj.tx;
/**
* Created by Administrator on 2019/12/29 0029.
*/
public class TransactionManager {
public void begin(){
System.out.println("开启事务");
}
public void commit(){
System.out.println("提交事务");
}
public void rollback(){
System.out.println("回滚事务");
}
}
3、dao
package com.xj.dao;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public interface IUserDao {
void save();
void update();
}
package com.xj.dao.impl;
import com.xj.dao.IUserDao;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public class UserDaoImpl implements IUserDao{
public void save() {
System.out.println("保存用户");
}
public void update() {
System.out.println("更新用户");
System.out.println(1/0);//出现异常
}
}
4、service
package com.xj.service;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public interface IUserService {
void save();
void update();
}
package com.xj.service.impl;
import com.xj.dao.IUserDao;
import com.xj.service.IUserService;
import com.xj.tx.TransactionManager;
import lombok.Setter;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public class UserServiceImpl implements IUserService{
@Setter
private IUserDao dao;
@Setter
private TransactionManager txManager;
public void save() {
try{
//开启事务
txManager.begin();
//业务操作
dao.save();
//提交事务
txManager.commit();
}catch(Exception e){
//回滚事务
txManager.rollback();
}
}
public void update() {
try{
//开启事务
txManager.begin();
//业务操作
dao.update();
//提交事务
txManager.commit();
}catch(Exception e){
//回滚事务
txManager.rollback();
}
}
}
5、applicationContext
<?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="txManager" class="com.xj.tx.TransactionManager"></bean>
<bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>
<bean id="service" class="com.xj.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
<property name="txManager" ref="txManager"/>
</bean>
</beans>
6、测试类
package com.xj;
import com.xj.service.IUserService;
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;
/**
* Created by Administrator on 2019/12/27 0027.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {
@Autowired
private IUserService service;
@Test
public void testSave(){
service.save();
}
@Test
public void testUpdate(){
service.update();
}
}
存在的问题: 每一个Service实现类中的方法,都得需要处理事务,而这些处理事务的代码结构其实是相同的,存在着代码重复的.
问题1: 处理事务的代码结构重复.
问题2: 在业务方法中只需要处理业务功能即可,不该处理事务(责任分离思想).
二、引出代理模式
从生活中去寻找解决方案,所以第一步找一个相似的案例:房屋中介案例
房东做了很多重复的并且不应该自己去做的事情:带你看房,商量租金,交钥匙. 她最感兴趣的是签合同和收房租. 房东就好比是Service实现类.
真实生活中有一种房屋中介是这样的,租客根本就不知道房东是谁,一切签合同、交租金、交钥匙等操作都直接和中介公司发生。我们把这种模式称之为代理模式。
代理模式:客户端直接使用的都是代理对象,不知道目标对象是谁,此时代理对象可以在客户端和目标对象之间起到中介的作用。
1、代理对象完全包含目标对象,客户端使用的都是代理对象的方法,和目标对象没有直接关系;
2、代理模式的职责:把不是目标对象该做的事情从目标对象上撇开——职责清晰;
静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和目标对象的关系在运行前就确定了。
动态代理:动态代理类是在程序运行期间由JVM通过反射等机制动态的生成的,所以不存在代理类的字节码文件。代理对象和真实对象的关系是在程序运行事情才确定的。
三、静态代理
静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在运行前就确定了。
新增一个代理类
package com.xj.proxy;
import com.xj.service.IUserService;
import com.xj.tx.TransactionManager;
import lombok.Setter;
/**
* Created by Administrator on 2019/12/29 0029.
*/
public class UserServiceImplProxy implements IUserService{ //代理类
@Setter
private IUserService target;
@Setter
private TransactionManager txManager;
public void save() {
try{
//开启事务
txManager.begin();
//业务操作
target.save();
//提交事务
txManager.commit();
}catch(Exception e){
//回滚事务
txManager.rollback();
}
}
public void update() {
try{
//开启事务
txManager.begin();
//业务操作
target.update();
//提交事务
txManager.commit();
}catch(Exception e){
//回滚事务
txManager.rollback();
}
}
}
修改真实类
package com.xj.service.impl;
import com.xj.dao.IUserDao;
import com.xj.service.IUserService;
import lombok.Setter;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public class UserServiceImpl implements IUserService{
@Setter
private IUserDao dao;
public void save() {
dao.save();
}
public void update() {
dao.update();
}
}
修改applicationContext
<!--事务管理器-->
<bean id="txManager" class="com.xj.tx.TransactionManager"></bean>
<bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>
<!--目标对象-->
<bean id="service" class="com.xj.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
</bean>
<!--代理对象-->
<bean id="proxy" class="com.xj.proxy.UserServiceImplProxy">
<property name="txManager" ref="txManager"/>
<property name="target" ref="service"/>
</bean>
修改测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {
@Autowired
@Qualifier("proxy")//存在两个实现类,要指定给代理对象的那个实现类
private IUserService service;
@Test
public void testSave(){
service.save();
}
@Test
public void testUpdate(){
service.update();
}
}
静态代理优缺点:
优点: 1.业务类只需要关注业务逻辑本身,保证了业务类的重用性。 2.把真实对象隐藏起来了,保护真实对象
缺点: 1.代理对象的某个接口只服务于某一种类型的对象,也就是说每一个真实对象都得创建一个代理对象。 2.如果需要代理的方法很多,则要为每一种方法都进行代理处理。 3.如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
四、动态代理
动态代理是在程序运行期间由JVM通过反射等机制动态的创建出代理对象的字节码。代理对象和真实对象的关系是在程序运行时才确定的。
动态代理是AOP的原理
1.jdk动态代理
JDK动态代理API分析:
1、java.lang.reflect.Proxy 类: Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
主要方法:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)
方法职责:为指定类加载器、一组接口 及 调用处理器生成动态代理类实例
参数: loader :类加载器 interfaces:目标对象实现的接口 hanlder:代理执行处理器
返回:动态生成的代理对象
1、添加依赖,事务管理器,参考上面案例
2、dao
package com.xj.dao;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public interface IUserDao {
void save();
void update();
}
package com.xj.dao.impl;
import com.xj.dao.IUserDao;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public class UserDaoImpl implements IUserDao{
public void save() {
System.out.println("保存用户");
}
public void update() {
System.out.println("更新用户");
System.out.println(1/0);//出现异常
}
}
3、service
package com.xj.service;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public interface IUserService {
void save();
void update();
}
package com.xj.service.impl;
import com.xj.dao.IUserDao;
import com.xj.service.IUserService;
import lombok.Setter;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public class UserServiceImpl implements IUserService{
@Setter
private IUserDao dao;
public void save() {
dao.save();
}
public void update() {
dao.update();
}
}
4、代理类
package com.xj.proxy;
import com.xj.tx.TransactionManager;
import lombok.Setter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created by Administrator on 2019/12/29 0029.
*/
public class JDKProxy implements InvocationHandler{
@Setter
private Object target;//可以给任意的目标做代理,只要目标实现了接口
@Setter
private TransactionManager txManager;
//获取代理对象
public Object getProxy(){
/*
* 第一个参数:类加载器
* 第二个参数:目标对象实现的接口的字节码数据对象 getClass获取字节码对象
* 第三个参数:实现了InvocationHandler接口的类的对象
* */
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try{
//开启事务
txManager.begin();
//执行业务方法
method.invoke(target,args);
//提交事务
txManager.commit();
}catch (Exception e){
//回滚事务
txManager.rollback();
}
return null;
}
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--事务管理器-->
<bean id="txManager" class="com.xj.tx.TransactionManager"></bean>
<bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>
<!--目标对象-->
<bean id="service" class="com.xj.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
</bean>
<!--事务增强的代理类-->
<bean id="jdkProxy" class="com.xj.proxy.JDKProxy">
<property name="target" ref="service"/>
<property name="txManager" ref="txManager"/>
</bean>
</beans>
6、测试类
package com.xj;
import com.xj.proxy.JDKProxy;
import com.xj.service.IUserService;
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;
/**
* Created by Administrator on 2019/12/27 0027.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {
@Autowired
private JDKProxy jdkProxy;
@Test
public void testSave(){
IUserService proxy = (IUserService) jdkProxy.getProxy();
proxy.save();
}
@Test
public void testUpdate(){
IUserService proxy = (IUserService) jdkProxy.getProxy();
proxy.update();
}
}
JDK动态代理:
1,代理的对象必须要实现接口
2,需要为每个对象创建代理对象;
3,动态代理的最小单位是类(类中所有的方法都会被代理);
JDK动态代理总结:
1,JAVA动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口这两个来完成的。
2,要使用JDK动态代理,必须要定义接口。
3,JDK动态代理将会拦截所有pubic的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。
4,如果只想拦截一部分方法,可以在invoke方法中对要执行的方法名进行判断。
2.jdk动态代理的实现原理
3.cglib的动态代理
针对于没有接口的类,如何做代理:cglib都是针对没有接口,做动态代理的.
原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
package com.xj.cglib;
import com.xj.service.impl.UserServiceImpl;
import com.xj.tx.TransactionManager;
import lombok.Setter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import java.lang.reflect.Method;
/**
* Created by Administrator on 2019/12/29 0029.
*/
public class CglibProxy implements InvocationHandler{
@Setter
private Object target;
@Setter
private TransactionManager txManager;
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback(this);
//返回一个代理对象
return enhancer.create();
}
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
try{
//开启事务
txManager.begin();
//执行业务方法
method.invoke(target,objects);
//提交事务
txManager.commit();
}catch (Exception e){
//回滚事务
txManager.rollback();
}
return null;
}
}
<bean id="cglibProxy" class="com.xj.cglib.CglibProxy">
<property name="target" ref="service"/>
<property name="txManager" ref="txManager"/>
</bean>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {
@Autowired
private JDKProxy jdkProxy;
@Autowired
private CglibProxy cglibProxy;
@Test
public void testSave(){
/* IUserService proxy = (IUserService) jdkProxy.getProxy();
System.out.println(proxy.getClass());
proxy.save();*/
UserServiceImpl proxy = (UserServiceImpl)cglibProxy.getProxy();
proxy.save();
}
@Test
public void testUpdate(){
/*IUserService proxy = (IUserService) jdkProxy.getProxy();
proxy.update();*/
UserServiceImpl proxy = (UserServiceImpl)cglibProxy.getProxy();
proxy.update();
}
}
CGLIB代理总结:
1,CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。
2,要求类不能是final的,要拦截的方法要是非final、非static、非private的。
3,动态代理的最小单位是类(所有类中的方法都会被处理);
在Spring中:
若目标对象实现了若干接口,Spring就会使用JDK动态代理。
若目标对象没有实现任何接口,Spring就使用CGLIB库生成目标对象的子类。
对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统,也更符合面向接口编程规范。
五、AOP的思想和概念
什么叫做AOP:Aspect oritention programming(面向切面编程)
把一个个的横切关注点(这些零散存在于业务方法中的功能代码,我们称之为横切面关注点)放到某个模块中去,称之为切面。那么每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。这种面向切面编程的思想就是AOP思想了。
AOP的目的: AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来, 便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
AOP的优势: 降低模块的耦合度、使系统容易扩展、更好的代码复用性 说人话: 把多个方法前/后的共同代码抽离出来,使用动态代理机制来控制,先执行抽离出来的代码,再执行每一个真实方法.
Spring的AOP使用动态代理实现: 如果一个类实现了接口,那么spring就使用JDK的动态代理完成AOP; 如果一个类没有实现接口,那么spring就是用cglib完成AOP;
AOP当中的概念:
Joinpoint:连接点,被拦截到需要被增强的方法。where:去哪里做增强
Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强
Advice:增强,当拦截到Joinpoint之后,在方法执行的什么时机(when)做什么样(what)的增强。
Aspect:切面,Pointcut+Advice,去哪些地方+在什么时候+做什么增强
Weaving:织入,把Advice加到Target上之后,创建出Proxy对象的过程。
六、pointcut语法
Pointcut语法: AOP思想本应该由SUN公司来制定规范,但是被AOP联盟捷足先登了. AOP联盟制定AOP规范,首先就要解决一个问题,怎么表示在哪些方法上增强—— AspectJ(语言)。
AspectJ切入点语法如下: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
翻译成中文: execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)
通配符:
* :匹配任何部分,只能表示一个单词
.. : 可用于全限定名中和方法参数中,分别表示子包和0到N个参数
七、aop的xml配置
1、添加依赖参考上面,另外新增。
<!-- aspectjweaverr -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
2、事务管理器,参考上面,新增destory方法
package com.xj.tx;
/**
* Created by Administrator on 2019/12/29 0029.
*/
public class TransactionManager {
public void begin(){
System.out.println("开启事务");
}
public void commit(){
System.out.println("提交事务");
}
public void rollback(){
System.out.println("回滚事务");
}
public void destory(){
System.out.println("释放资源");
}
}
3、dao
package com.xj.dao;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public interface IUserDao {
void save();
void update();
}
package com.xj.dao.impl;
import com.xj.dao.IUserDao;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public class UserDaoImpl implements IUserDao{
public void save() {
System.out.println("保存用户");
}
public void update() {
System.out.println("更新用户");
System.out.println(1/0);//出现异常
}
}
4、service
package com.xj.service;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public interface IUserService {
void save();
void update();
}
package com.xj.service.impl;
import com.xj.dao.IUserDao;
import com.xj.service.IUserService;
import lombok.Setter;
/**
* Created by Administrator on 2019/12/27 0027.
*/
public class UserServiceImpl implements IUserService{
@Setter
private IUserDao dao;
public void save() {
dao.save();
}
public void update() {
dao.update();
}
}
5、配置xml文件,(添加aop命名空间,配置切入点,切入面)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--事务管理器-->
<bean id="txManager" class="com.xj.tx.TransactionManager"></bean>
<bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>
<!--目标对象-->
<bean id="service" class="com.xj.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
</bean>
<!--配置AOP-->
<aop:config >
<!--
pointcut:切入点:哪些包里的哪些类中的哪些方法,需要被增强
-->
<aop:pointcut id="txPointxut" expression="execution( * com.xj.service.IUserService.*(..))"></aop:pointcut>
<!--
配置切面:Aspect = pointcut+Advice
-->
<aop:aspect ref="txManager">
<!--前置增强-->
<aop:before method="begin" pointcut-ref="txPointxut"/>
<!--后置增强-->
<aop:after-returning method="commit" pointcut-ref="txPointxut"/>
<!--异常增强-->
<aop:after-throwing method="rollback" pointcut-ref="txPointxut"/>
<!--最终增强-->
<aop:after method="destory" pointcut-ref="txPointxut"/>
</aop:aspect>
</aop:config>
</beans>
6、测试类
package com.xj;
import com.xj.service.IUserService;
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;
/**
* Created by Administrator on 2019/12/27 0027.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {
@Autowired
private IUserService service;
@Test
public void testSave(){
service.save();
}
@Test
public void testUpdate(){
service.update();
}
}
小结:
1.使用Spring的aop,首先要导入aspect包
2.Spring配置文件中添加aop的命名空间.
3.xml配置aop时,时刻记得要配置where,when,what.
八、不同时机的增强
各种不同的增强:
aop:before(前置增强):在方法执行之前执行增强;
aop:after-returning(后置增强):在方法正常执行完成之后执行增强;
aop:after-throwing(异常增强):在方法抛出异常退出时执行增强;
aop:after(最终增强):在方法执行之后执行,相当于在finally里面执行;可以通过配置throwing来获得拦截到的异常信息
aop:around(环绕增强):最强大的一种增强类型。 环绕增强可以在方法调用前后完成自定义的行为,
环绕增强有两个要求:
1,方法要返回一个Object(返回的结果)
2,方法的第一个参数是ProceedingJoinPoint(可以继续向下传递的切入点)
案例:使用环绕增强,在七的代码上进行添加修改
1、在事务管理器中添加around方法
public void around(ProceedingJoinPoint pj) {
try {
System.out.println("开启事务");
//执行被增强的方法
pj.proceed();//这个方法可以有一个返回值,比如 save方法返回值是Integer 这就可以返回一个值Object i =pj.proceed() ,然后return i;
//注:around返回类型要写成Object; update没有返回值,不影响
System.out.println("提交事务");
} catch (Throwable e) {
System.out.println("回滚事务");
} finally {
System.out.println("释放资源");
}
}
2、修改配置文件
<!--配置AOP-->
<aop:config >
<!--
pointcut:切入点:哪些包里的哪些类中的哪些方法,需要被增强
-->
<aop:pointcut id="txPointxut" expression="execution( * com.xj.service.IUserService.*(..))"></aop:pointcut>
<!--
配置切面:Aspect = pointcut+Advice
-->
<aop:aspect ref="txManager">
<!--前置增强-->
<!-- <aop:before method="begin" pointcut-ref="txPointxut"/>-->
<!--后置增强-->
<!-- <aop:after-returning method="commit" pointcut-ref="txPointxut"/>-->
<!--异常增强-->
<!-- <aop:after-throwing method="rollback" pointcut-ref="txPointxut"/>-->
<!--最终增强-->
<!--<aop:after method="destory" pointcut-ref="txPointxut"/>-->
<!--环绕增强-->
<aop:around method="around" pointcut-ref="txPointxut"/>
</aop:aspect>
九、获取增强的参数
1、在增强方法中获取异常的信息。
<aop:after-throwing>的标签中添加throwing=“ex”的属性
增强方法rollback中,添加形式参数:Exception ex。
则,形参ex中就自动注入了异常对象。
注意:throwing属性的值,必须与方法中形参的名字相同
案例:执行update方法
(1)使用环绕增强,获取异常参数
(2)使用其他增强方式获取增强参数
2、在增强方法中,获取被增强方法的信息:
Spring AOP提供org.aspectj.lang.JoinPoint类,作为增强方法的第一个参数。
JoinPoint :提供访问当前被增强方法的真实对象、代理对象、方法参数等数据。
ProceedingJoinPoint:JinPoint子类,只用于环绕增强中,可以处理被增强方法。
十、aop的注解配置
1、添加依赖,参考上面
2、事务管理器
package com.xj.tx;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
/**
* Created by Administrator on 2019/12/29 0029.
*/
@Aspect
public class TransactionManager {
@Pointcut("execution( * com.xj.service.IUserService.*(..))")
public void tx(){}
@Before("tx()")
public void begin(JoinPoint jp){//获取增强参数
System.out.println("开启事务");
System.out.println(jp.getThis());
}
@AfterReturning("tx()")
public void commit(){
System.out.println("提交事务");
}
@AfterThrowing(value="tx()",throwing = "ex")//获取异常参数
public void rollback(Exception ex){
System.out.println("回滚事务");
System.out.println(ex.getMessage());
}
@After("tx()")
public void destory(){
System.out.println("释放资源");
}
}
3、dao和servive参考上个例子
4、配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--事务管理器-->
<bean id="txManager" class="com.xj.tx.TransactionManager"></bean>
<bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>
<!--目标对象-->
<bean id="service" class="com.xj.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
</bean>
<!--aop注解解析器-->
<aop:aspectj-autoproxy/>
</beans>
5、测试类
package com.xj;
import com.xj.service.IUserService;
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;
/**
* Created by Administrator on 2019/12/27 0027.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {
@Autowired
private IUserService service;
@Test
public void testSave(){
service.save();
}
@Test
public void testUpdate(){
service.update();
}
}