使用springaop技术面向切面编程
2019-05-24 13:41
603 查看
[code]手写Spring的事务框架,SpringAOP的技术你们用过没有,Spring事务分为两种,一种叫编程式事务,一种叫声明式事务, 我讲一下SpringAOP的技术怎么用,项目jar包依赖信息,因为我们会用到数据源,要做事务处理,第一步把所有的jar包 copy进来
[code]<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.learn</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/javassist/javassist --> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <!-- 引入Spring-AOP等相关Jar --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.1_2</version> </dependency> <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> </dependencies> </project>
[code]是简单的搭建一个Spring的环境,事务,AOP,因为我们待会会用到的,然后在这个地方我们就来做个操作,给他简单的用一下 Spring的AOP,有两种实现方式,在SpringAOP的技术里面,一种叫做注解版本,还有一种是XML版本,我告诉你们,我一般是用注解 版本的,很多去用xml版本的,为什么呢,因为你们以后会学一个SpringBoot的,你们以后尽量不要写xml,因为你们发现用SpringBoot 的时候,你根本就不写xml了,全都是自动化的,全部都是注解版本的,所以我们讲一下,xml版本我相信,在今后几年当中, 都会淘汰的,通过注解方式替代xml方式,今天我主要讲注解版本,不去讲xml版本了,你们可以自己去看看,我就不说了, 那怎么去用呢,这个用法就比较简单,大家想一下AOP的几个点,然后我再去讲一下代码如何去整合,然后在这里给大家说一下
[code]package com.learn.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * 做一个日志的处理 * 这个类干嘛的呢 * 其实就是切面类 * 把我们重复的代码全部放在AOP里面去 * 这个代码怎么写 * 首先记住这里加一个注解 * @Apect表示这是一个切面类了 * 然后放在容器里面去的@Component * * @author Leon.Sun * */ @Component @Aspect public class AogLog { /** * 在这里我们怎么去做处理呢 * 首先这里有几个方法一定要认真听一下 * SpringAOP里面有几个通知 * 第一个叫前置通知 * 还有一个叫后置通知 * 还又叫运行通知 * 还有叫异常通知 * 环绕通知 * 我一个个讲 * * 这个通知我们就叫做前置通知 * * 前置通知到底是干嘛目的 * 你要写一个表达式 * 切入点的表达式 * 这是我要给你们说一下 * 切入点是啥意思 * 假如你要拦截哪些方法 * "execution(* com.learn.service.UserService.add(..))" * 你们看一下是什么意思啊 * 这个表达式是做什么目的的 * 表示我会去拦截com.learn.service.UserService这个类的add的方法 * 我会在这个方法之前做一个拦截 * 这个方法叫前置通知 * */ @Before("execution(* com.learn.service.UserService.add(..))") public void before() { /** * 在方法之前执行 * */ System.out.println("前置通知 在方法之前执行..."); } /** * 我们在这里可以写一个后置通知 * 这个叫后置通知 * 后置通知里我要怎么去写呢 * 这个我们怎么写 * 后置通知 在方法运行后执行 * "execution(* com.learn.service.UserService.add(..))" * 我把这个表达式也copy过来 */ @After("execution(* com.learn.service.UserService.add(..))") public void after() { /** * 在方法后执行 */ System.out.println("后置通知 在方法之后执行..."); } /** * 我依次类推 * 运行通知 * 首先这个通知是干嘛用的 * 就是方法运行的时候就有这个通知 */ @AfterReturning("execution(* com.learn.service.UserService.add(..))") public void returning() { System.out.println("运行通知"); } /** * 这个表示在方法异常的情况下会有异常通知的 * 大家不要小看异常通知 * 为什么Spring事务为什么会失效呢 * 就是我没有注意异常 * 我待会会细说的 * * */ @AfterThrowing("execution(* com.learn.service.UserService.add(..))") public void afterThrowing() { System.out.println("异常通知"); } /** * 这个也是我们会经常用的环绕通知 * 环绕通知里面是怎么写的呢 * 环绕通知 在方法之前和之后处理事情 * ProceedingJoinPoint传进来 * 这个方法怎么用的呢 * 就好比他在实际调用你的add方法 * * 其实你们可以把表达式抽取出来 * 我先这样写 * 你们可以把表达式封装成一个 * 这也是可以的 * * * @param proceedingJoinPoint * @throws Throwable */ @Around("execution(* com.learn.service.UserService.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { /** * 调用方法之前执行 */ System.out.println("环绕通知 调用方法之前执行"); /** * 这里有一个方法 * 代理调用方法 注意点: 如果调用方法抛出溢出不会执行后面代码 * 相当于invoke * 这个方法非常核心 * 你们使用Spring事务的时候为什么会失效呢 * 如果没有抛出这个异常 * 如果你的调用方法抛出异常 * 假设你抛出异常的情况下 * 他就会怎么样进行处理呢 * 不会执行后面的代码 * 这是什么意思啊 * 比如代理调用方法的时候 * 假设去调用add方法的时候 * 如果add方法里面突然报了一个错 * 他就不会往后面继续执行的 * 这是我要给你们说的 * 所以你们使用事务的时候不要去try * 一定要抛出去 * 抛的话会导致什么问题呢 * 事务提交到数据库里面去了 * 你这样会回滚的 * 那肯定不好 */ proceedingJoinPoint.proceed(); /** * 调用方法之后执行 */ System.out.println("环绕通知 调用方法之后执行"); } }
[code]<?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:context="http://www.springframework.org/schema/context" 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/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"> <!-- 这里表示扫包范围 因为我们是使用注解的, --> <context:component-scan base-package="com.learn"></context:component-scan> <!-- 这里表示开启事务的注解 你如果想要事务的话,你必须开启一个事务注解, --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 开启事物注解 --> <!-- 1. 数据源对象: C3P0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localho 7ff7 st:3306/test"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!-- 2. JdbcTemplate工具类实例 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 3.配置事务 --> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> </beans>
[code]package com.learn.service.impl; import org.springframework.stereotype.Service; import com.learn.service.UserService; /** * 加上注解之后 * @author Leon.Sun * */ @Service public class UserServiceImpl implements UserService { public void add() { try { int i = 10 /0; System.out.println("################往数据库添加数据#################"); } catch (Exception e) { } } }
[code]package com.learn.service; public interface UserService { public void add(); }
[code]package com.learn.test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.learn.service.UserService; /** * 我们看一下AOP能不能成功 * @author Leon.Sun * */ public class Test001 { public static void main(String[] args) { /** * new一下ClassPathXmlApplicationContext * 表示读取到我们的spring.xml配置文件 * */ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); /** * 这样拿到我们的user接口 * 把它强转一下 * */ UserService userService = (UserService) applicationContext.getBean("userServiceImpl"); /** * 前置通知 * 环绕通知之前 * 往数据库里添加代码 * 后置通知 * 运行通知 * 环绕通知之后 * * 异常通知现在有没有运行过 * 为什么 * 因为我的方法没有抛异常 * 怎么可能运行我的异常通知 * 我在add方法里面写一个 int i = 10 /0 * 写完之后我们看一下效果 * 是不是报错了 * 异常通知 * 你们看一下环绕通知之后有没有再运行 * 环绕通知之后就会打印这段代码 * 有没有执行 * 因为它报错了 * 只要你调用的方法报错的情况下 * 他不会执行的 * 这边我就给你演示一个错误 * * 比如我把它try一下 * 这个时候环绕通知之后的代码会不会执行 * 环绕通知之后会不会执行 * 会还是不会 * 这肯定会 * 因为他没有把异常抛出来 * 肯定是会的 * 环绕方法调用之前和环绕方法调用之后 * 这个时候就把注解版的事务讲完了 * 还有xml方式我就不去讲了 * * * */ userService.add(); } } //前置通知 在方法之前执行... //环绕通知 调用方法之前执行 //################往数据库添加数据################# //后置通知 在方法之后执行... //运行通知 //环绕通知 调用方法之后执行 //前置通知 在方法之前执行... //Exception in thread "main" java.lang.ArithmeticException: / by zero // at com.learn.service.impl.UserServiceImpl.add(UserServiceImpl.java:16) // at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) // at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) //环绕通知 调用方法之前执行 //后置通知 在方法之后执行... //异常通知
[code]<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 开启事物注解权限 @Aspect 指定一个类为切面类 @Pointcut("execution(* com.itmayiedu.service.UserService.add(..))") 指定切入点表达式 @Before("pointCut_()") 前置通知: 目标方法之前执行 @After("pointCut_()") 后置通知:目标方法之后执行(始终执行) @AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行) @AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行 @Around("pointCut_()") 环绕通知: 环绕目标方法执行
[code]XML方式实现AOP Xml实现aop编程: 1) 引入jar文件 【aop 相关jar, 4个】 2) 引入aop名称空间 3)aop 配置 * 配置切面类 (重复执行代码形成的类) * aop配置 拦截哪些方法 / 拦截到方法后应用通知代码
[code]<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:context="http://www.springframework.org/schema/context" 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/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"> <!-- dao 实例 --> <bean id="userService" class="com.learn.service.UserService"></bean> <!-- 切面类 --> <bean id="aop" class="com.learn.aop.AopLog"></bean> <!-- Aop配置 --> <aop:config> <!-- 定义一个切入点表达式: 拦截哪些方法 --> <aop:pointcut expression="execution(* com.learn.service.UserService.*(..))" id="pt" /> <!-- 切面 --> <aop:aspect ref="aop"> <!-- 环绕通知 --> <aop:around method="around" pointcut-ref="pt" /> <!-- 前置通知: 在目标方法调用前执行 --> <aop:before method="begin" pointcut-ref="pt" /> <!-- 后置通知: --> <aop:after method="after" pointcut-ref="pt" /> <!-- 返回后通知 --> <aop:after-returning method="afterReturning" pointcut-ref="pt" /> <!-- 异常通知 --> <aop:after-throwing method="afterThrowing" pointcut-ref="pt" /> </aop:aspect> </aop:config> </beans>
相关文章推荐
- Spring学习之旅(二) AOP(面向切面编程)的使用
- Spring(十一)使用Spring的注解方式实现面向切面技术AOP
- Spring学习笔记 —— AOP(面向切面编程) 之使用ProxyFactoryBean实现AOP
- Spring面向切面编程(AOP)原理二之使用Cglib实现动态代理
- Spring面向切面编程(AOP)原理一之使用JDK实现动态代理
- Java面试--Spring技术要点--Spring AOP(面向切面编程)
- Spring——使用Spring的注解方式实现面向切面技术AOP
- Spring面向切面编程(AOP)三之AOP的使用及XML配置
- 深入探索spring技术内幕(七): 配置Spring AOP面向切面编程
- Spring AOP-->面向切面编程简单理解和简单使用
- 深入探索spring技术内幕(七): 配置Spring AOP面向切面编程
- spring面向切面编程(aop)
- 使用Spring进行面向切面(AOP)编程
- Spring----AOP面向切面编程例子解析(附源码)
- Spring笔记——使用Spring进行面向切面(AOP)编程
- Spring面向切面编程(AOP)方式二
- Spring面向切面编程(AOP)
- Spring AOP 面向切面编程(一)
- Spring AOP面向切面编程
- Spring学习之AOP(面向切面编程)