使用springaop技术面向切面编程
生活随笔
收集整理的這篇文章主要介紹了
使用springaop技术面向切面编程
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
手寫Spring的事務(wù)框架,SpringAOP的技術(shù)你們用過沒有,Spring事務(wù)分為兩種,一種叫編程式事務(wù),一種叫聲明式事務(wù),我講一下SpringAOP的技術(shù)怎么用,項(xiàng)目jar包依賴信息,因?yàn)槲覀儠?huì)用到數(shù)據(jù)源,要做事務(wù)處理,第一步把所有的jar包c(diǎn)opy進(jìn)來
<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等相關(guān)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>
是簡(jiǎn)單的搭建一個(gè)Spring的環(huán)境,事務(wù),AOP,因?yàn)槲覀兇龝?huì)會(huì)用到的,然后在這個(gè)地方我們就來做個(gè)操作,給他簡(jiǎn)單的用一下Spring的AOP,有兩種實(shí)現(xiàn)方式,在SpringAOP的技術(shù)里面,一種叫做注解版本,還有一種是XML版本,我告訴你們,我一般是用注解版本的,很多去用xml版本的,為什么呢,因?yàn)槟銈円院髸?huì)學(xué)一個(gè)SpringBoot的,你們以后盡量不要寫xml,因?yàn)槟銈儼l(fā)現(xiàn)用SpringBoot的時(shí)候,你根本就不寫xml了,全都是自動(dòng)化的,全部都是注解版本的,所以我們講一下,xml版本我相信,在今后幾年當(dāng)中,都會(huì)淘汰的,通過注解方式替代xml方式,今天我主要講注解版本,不去講xml版本了,你們可以自己去看看,我就不說了,那怎么去用呢,這個(gè)用法就比較簡(jiǎn)單,大家想一下AOP的幾個(gè)點(diǎn),然后我再去講一下代碼如何去整合,然后在這里給大家說一下
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;/*** 做一個(gè)日志的處理* 這個(gè)類干嘛的呢* 其實(shí)就是切面類* 把我們重復(fù)的代碼全部放在AOP里面去* 這個(gè)代碼怎么寫* 首先記住這里加一個(gè)注解* @Apect表示這是一個(gè)切面類了* 然后放在容器里面去的@Component* * @author Leon.Sun**/
@Component
@Aspect
public class AogLog {/*** 在這里我們?cè)趺慈プ鎏幚砟? 首先這里有幾個(gè)方法一定要認(rèn)真聽一下* SpringAOP里面有幾個(gè)通知* 第一個(gè)叫前置通知* 還有一個(gè)叫后置通知* 還又叫運(yùn)行通知* 還有叫異常通知* 環(huán)繞通知* 我一個(gè)個(gè)講* * 這個(gè)通知我們就叫做前置通知* * 前置通知到底是干嘛目的* 你要寫一個(gè)表達(dá)式* 切入點(diǎn)的表達(dá)式* 這是我要給你們說一下* 切入點(diǎn)是啥意思* 假如你要攔截哪些方法* "execution(* com.learn.service.UserService.add(..))"* 你們看一下是什么意思啊* 這個(gè)表達(dá)式是做什么目的的* 表示我會(huì)去攔截com.learn.service.UserService這個(gè)類的add的方法* 我會(huì)在這個(gè)方法之前做一個(gè)攔截* 這個(gè)方法叫前置通知* */@Before("execution(* com.learn.service.UserService.add(..))")public void before() {/*** 在方法之前執(zhí)行* */System.out.println("前置通知 在方法之前執(zhí)行...");}/*** 我們?cè)谶@里可以寫一個(gè)后置通知* 這個(gè)叫后置通知* 后置通知里我要怎么去寫呢* 這個(gè)我們?cè)趺磳? 后置通知 在方法運(yùn)行后執(zhí)行* "execution(* com.learn.service.UserService.add(..))"* 我把這個(gè)表達(dá)式也copy過來*/@After("execution(* com.learn.service.UserService.add(..))")public void after() {/*** 在方法后執(zhí)行*/System.out.println("后置通知 在方法之后執(zhí)行...");}/*** 我依次類推* 運(yùn)行通知* 首先這個(gè)通知是干嘛用的* 就是方法運(yùn)行的時(shí)候就有這個(gè)通知*/@AfterReturning("execution(* com.learn.service.UserService.add(..))")public void returning() {System.out.println("運(yùn)行通知");}/*** 這個(gè)表示在方法異常的情況下會(huì)有異常通知的* 大家不要小看異常通知* 為什么Spring事務(wù)為什么會(huì)失效呢* 就是我沒有注意異常* 我待會(huì)會(huì)細(xì)說的* * */@AfterThrowing("execution(* com.learn.service.UserService.add(..))")public void afterThrowing() {System.out.println("異常通知");}/*** 這個(gè)也是我們會(huì)經(jīng)常用的環(huán)繞通知* 環(huán)繞通知里面是怎么寫的呢* 環(huán)繞通知 在方法之前和之后處理事情* ProceedingJoinPoint傳進(jìn)來* 這個(gè)方法怎么用的呢* 就好比他在實(shí)際調(diào)用你的add方法* * 其實(shí)你們可以把表達(dá)式抽取出來* 我先這樣寫* 你們可以把表達(dá)式封裝成一個(gè)* 這也是可以的* * * @param proceedingJoinPoint* @throws Throwable*/@Around("execution(* com.learn.service.UserService.add(..))")public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{/*** 調(diào)用方法之前執(zhí)行*/System.out.println("環(huán)繞通知 調(diào)用方法之前執(zhí)行");/*** 這里有一個(gè)方法* 代理調(diào)用方法 注意點(diǎn): 如果調(diào)用方法拋出溢出不會(huì)執(zhí)行后面代碼* 相當(dāng)于invoke* 這個(gè)方法非常核心* 你們使用Spring事務(wù)的時(shí)候?yàn)槭裁磿?huì)失效呢* 如果沒有拋出這個(gè)異常* 如果你的調(diào)用方法拋出異常* 假設(shè)你拋出異常的情況下* 他就會(huì)怎么樣進(jìn)行處理呢* 不會(huì)執(zhí)行后面的代碼* 這是什么意思啊* 比如代理調(diào)用方法的時(shí)候* 假設(shè)去調(diào)用add方法的時(shí)候* 如果add方法里面突然報(bào)了一個(gè)錯(cuò)* 他就不會(huì)往后面繼續(xù)執(zhí)行的* 這是我要給你們說的* 所以你們使用事務(wù)的時(shí)候不要去try* 一定要拋出去* 拋的話會(huì)導(dǎo)致什么問題呢* 事務(wù)提交到數(shù)據(jù)庫(kù)里面去了* 你這樣會(huì)回滾的* 那肯定不好*/proceedingJoinPoint.proceed();/*** 調(diào)用方法之后執(zhí)行*/System.out.println("環(huán)繞通知 調(diào)用方法之后執(zhí)行");}
}
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 這里表示掃包范圍 因?yàn)槲覀兪鞘褂米⒔獾?--><context:component-scan base-package="com.learn"></context:component-scan><!-- 這里表示開啟事務(wù)的注解 你如果想要事務(wù)的話,你必須開啟一個(gè)事務(wù)注解,--><aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 開啟事物注解 --><!-- 1. 數(shù)據(jù)源對(duì)象: 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://localhost:3306/test"></property><property name="user" value="root"></property><property name="password" value="root"></property></bean><!-- 2. JdbcTemplate工具類實(shí)例 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><!-- 3.配置事務(wù) --><bean id="dataSourceTransactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean></beans>
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("################往數(shù)據(jù)庫(kù)添加數(shù)據(jù)#################");} catch (Exception e) {}}}
package com.learn.service;public interface UserService {public void add();
}
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接口* 把它強(qiáng)轉(zhuǎn)一下* */UserService userService = (UserService) applicationContext.getBean("userServiceImpl");/*** 前置通知* 環(huán)繞通知之前* 往數(shù)據(jù)庫(kù)里添加代碼* 后置通知* 運(yùn)行通知* 環(huán)繞通知之后* * 異常通知現(xiàn)在有沒有運(yùn)行過* 為什么* 因?yàn)槲业姆椒]有拋異常* 怎么可能運(yùn)行我的異常通知* 我在add方法里面寫一個(gè) int i = 10 /0* 寫完之后我們看一下效果* 是不是報(bào)錯(cuò)了* 異常通知* 你們看一下環(huán)繞通知之后有沒有再運(yùn)行* 環(huán)繞通知之后就會(huì)打印這段代碼* 有沒有執(zhí)行* 因?yàn)樗鼒?bào)錯(cuò)了* 只要你調(diào)用的方法報(bào)錯(cuò)的情況下* 他不會(huì)執(zhí)行的* 這邊我就給你演示一個(gè)錯(cuò)誤* * 比如我把它try一下* 這個(gè)時(shí)候環(huán)繞通知之后的代碼會(huì)不會(huì)執(zhí)行* 環(huán)繞通知之后會(huì)不會(huì)執(zhí)行* 會(huì)還是不會(huì)* 這肯定會(huì)* 因?yàn)樗麤]有把異常拋出來* 肯定是會(huì)的* 環(huán)繞方法調(diào)用之前和環(huán)繞方法調(diào)用之后* 這個(gè)時(shí)候就把注解版的事務(wù)講完了* 還有xml方式我就不去講了* * * */userService.add();}}//前置通知 在方法之前執(zhí)行...
//環(huán)繞通知 調(diào)用方法之前執(zhí)行
//################往數(shù)據(jù)庫(kù)添加數(shù)據(jù)#################
//后置通知 在方法之后執(zhí)行...
//運(yùn)行通知
//環(huán)繞通知 調(diào)用方法之后執(zhí)行//前置通知 在方法之前執(zhí)行...
//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)
//環(huán)繞通知 調(diào)用方法之前執(zhí)行
//后置通知 在方法之后執(zhí)行...
//異常通知
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 開啟事物注解權(quán)限
@Aspect 指定一個(gè)類為切面類
@Pointcut("execution(* com.itmayiedu.service.UserService.add(..))") 指定切入點(diǎn)表達(dá)式
@Before("pointCut_()") 前置通知: 目標(biāo)方法之前執(zhí)行
@After("pointCut_()") 后置通知:目標(biāo)方法之后執(zhí)行(始終執(zhí)行)
@AfterReturning("pointCut_()") 返回后通知: 執(zhí)行方法結(jié)束前執(zhí)行(異常不執(zhí)行)
@AfterThrowing("pointCut_()") 異常通知: 出現(xiàn)異常時(shí)候執(zhí)行
@Around("pointCut_()") 環(huán)繞通知: 環(huán)繞目標(biāo)方法執(zhí)行
XML方式實(shí)現(xiàn)AOPXml實(shí)現(xiàn)aop編程:1) 引入jar文件 【aop 相關(guān)jar, 4個(gè)】2) 引入aop名稱空間3)aop 配置* 配置切面類 (重復(fù)執(zhí)行代碼形成的類)* aop配置攔截哪些方法 / 攔截到方法后應(yīng)用通知代碼
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- dao 實(shí)例 --><bean id="userService" class="com.learn.service.UserService"></bean><!-- 切面類 --><bean id="aop" class="com.learn.aop.AopLog"></bean><!-- Aop配置 --><aop:config><!-- 定義一個(gè)切入點(diǎn)表達(dá)式: 攔截哪些方法 --><aop:pointcut expression="execution(* com.learn.service.UserService.*(..))"id="pt" /><!-- 切面 --><aop:aspect ref="aop"><!-- 環(huán)繞通知 --><aop:around method="around" pointcut-ref="pt" /><!-- 前置通知: 在目標(biāo)方法調(diào)用前執(zhí)行 --><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>
?
總結(jié)
以上是生活随笔為你收集整理的使用springaop技术面向切面编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 动态代理设计模式
- 下一篇: spring声明事务与编程事务概述