您的位置:首页 > 编程语言 > Java开发

使用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>

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: