天天看點

SpringAOP面向切面程式設計1

JDK動态代理

代理設計模式的原理: 使用一個代理将對象包裝起來, 然後用該代理對象取代原始對象. 任何對原始對象的調用都要通過代理. 代理對象決定是否以及何時将方法調用轉到原始對象上。

ServiceProxy.java    代理類,由此類建立代理對象來進行代理。

package com.zzxtit.spring.aop.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ServiceProxy implements InvocationHandler{

	private Object target;
	
	
	
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		System.out.println("方法:" + method.getName() + "被執行");
		
		for(Object arg : args) {
			System.out.println("-參數:" + arg);
		}
		
		Object returnValue = method.invoke(target, args);
		
		System.out.println("方法:" + method.getName() + "執行完畢,傳回值:" + returnValue);
		
		return returnValue;
	}

	
	public Object createProxy(Object target) {
		
		this.target = target;
		
		return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
	}
	
}
           

BankService.java     對象接口類

package com.zzxtit.spring.aop.proxy;

import java.math.BigDecimal;

public interface BankService {

	public void transfer(String target, String source, BigDecimal money);
	
	public String withdraw(String account, BigDecimal money);
}
           

BankServiceImpl.java 對象接口實作類

package com.zzxtit.spring.aop.proxy;

import java.math.BigDecimal;

public class BankServiceImpl implements BankService {

	public void transfer(String target, String source, BigDecimal money) {
		
		
		System.out.println("方法:transfer 被執行,參數:" + target + ", 參數:" + source + ", 參數:" + money);
		
	}
	
	public String withdraw(String account, BigDecimal money) {
		
		return "hello AOP";
	}

}
           

Main.java     測試類

package com.zzxtit.spring.aop.proxy;

import java.math.BigDecimal;

public class Main {

	public static void main(String[] args) {
		
		BankService bs = new BankServiceImpl();
//		bs.transfer("張三", "李四", new BigDecimal("123456"));
		
		// JDK 動态代理
		
		BankService bsProxy = (BankService) new ServiceProxy().createProxy(bs);
//		bsProxy.transfer("張三", "李四", new BigDecimal("123456"));
		bsProxy.withdraw( "李四", new BigDecimal("500"));
	}
}
           

AOP開發模式介紹

AOP(Aspect-Oriented Programming:  面向切面程式設計): 是一種一種程式設計範式,是對傳統 OOP(Object-Oriented Programming, 面向對象程式設計) 的補充.

AOP 的主要程式設計對象是切面(aspect), 而切面子產品化橫切關注點。

比如在處理業務操作時,我們想在其中某個步驟添加某些操作,或者列印日志,不對原來的代碼進行修改就可以增加功能

AOP 的好處:

1.降低子產品耦合度

2.使系統容易擴充

3.更好的代碼複用性

AOP 術語

SpringAOP面向切面程式設計1

Spring AOP相關Jar包 spring-aop-4.3.3.RELEASE.jar, aspectjweaver-1.8.5.jar aspectjrt-1.8.5.jar      

在XML檔案中手動配置

在xml檔案中需添加命名空間 xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=         http://www.springframework.org/schema/aop

        https://www.springframework.org/schema/aop/spring-aop.xsd

<aop:config>
		<aop:pointcut expression="execution(* springboot.aop.xml.BankServiceImpl.*(..))" id="loggerPointCut"/>
		<aop:aspect ref="loggerAspect">
			<aop:before method="logerBefore" pointcut-ref="loggerPointCut"/>
			
			<aop:after method="logerAfter" pointcut-ref="loggerPointCut"/>
		
			<aop:after-returning method="logerAfterReturning" pointcut-ref="loggerPointCut" returning="returnValue"/>
			
			<aop:around method="logerAround" pointcut-ref="loggerPointCut"/>
			
			<aop:after-throwing method="loggerAfterThrowing" pointcut-ref="loggerPointCut"  throwing="exception"/>
		</aop:aspect>
           

spring AOP 面向切面編程:攔截方法進行操作

表達式:expression="execution(* springboot.aop.xml.*.*(..))"

        第一個* 表示不限制傳回值類型

        第二個* 表示springboot.aop.xml包下所有的JAVA BEAN

        第三個* javabean 所有的方法

        (..) 表示對方法的參數沒有限制

LoggerAspect.java   日志切面類

package springboot.aop.xml;

import java.math.BigDecimal;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class LoggerAspect {

	
	public void logerBefore(JoinPoint jp) {
		String methodName = jp.getSignature().getName();
		System.out.println("method: " + methodName + "将要被執行!");
		
		Object[] args = jp.getArgs();
		for(Object arg : args) {
			System.out.println("=============參數:>" + arg);
		}
		
	}
	
	
	public void logerAfter(JoinPoint jp) {
		String methodName = jp.getSignature().getName();
		System.out.println("method: " + methodName + "已經被執行!");
		
		Object[] args = jp.getArgs();
		for(Object arg : args) {
			System.out.println("=============參數:>" + arg);
		}
	}
	
	public void logerAfterReturning(JoinPoint jp, Object returnValue) {
		String methodName = jp.getSignature().getName();
		System.out.println("後置傳回通知 =========>method: " + methodName + "已經被執行!");
		System.out.println("後置傳回通知的傳回值:" + returnValue);
	}
	
	//環繞通知 需要配置傳回值,否則目标方法所有的傳回值為null	
	public Object logerAround(ProceedingJoinPoint pjp) {
		String methodName = pjp.getSignature().getName();
		System.out.println("環繞通知 =========>method: " + methodName + "方法正在執行!");
		Object[] args = pjp.getArgs();//獲得參數
		args[0] = "測試資料";
		try {
			Object returnValue = pjp.proceed(args);
			
			System.out.println("環繞通知 =========>method: " + methodName + "已經被執行,傳回值:! " + returnValue);
//			returnValue = "hello World!!";
			return new BigDecimal("999999999999999");
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public void loggerAfterThrowing(JoinPoint jp, Exception exception) {
		System.out.println("後置異常通知:" + exception);
	}
}
           

BankService.java 銀行業務接口類

package springboot.aop.xml;

import java.math.BigDecimal;

public interface BankService {

	public BigDecimal transfer(String target, String source, BigDecimal money);
	
	
	public void test();
}
           

BankServiceImpl.java  銀行業務實作類

package springboot.aop.xml;

import java.math.BigDecimal;

public class BankServiceImpl implements BankService{

	
	public BigDecimal transfer(String target, String source, BigDecimal money) {
		System.out.println(source + "向" + target + "轉賬:" + money);
		
		throw new RuntimeException("故意出的異常!!");
		
//		return new BigDecimal("12345612");
	}

	public void test() {
		System.out.println("=============BankServiceImpl=====test===========>");
	}

}
           

Main.java         測試類

package springboot.aop.xml;

import java.math.BigDecimal;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

	public static void main(String[] args) {
		
		ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext-xml-aop.xml");
		
		BankService bs = ioc.getBean("bankService", BankService.class);
		
		bs.transfer("目标1", "目标2", new BigDecimal("100000000"));
	}
}
           

基于注解配置

首先要在XML檔案中添加類掃描器和配置

<context:component-scan base-package="com.zzxtit.spring.aop.anno"></context:component-scan>

	<!-- 開啟spring AOP 注解方式 自動代理 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
           

切面類需要用@Aspect注解标注,@Component将這個類标記為切面的Spring Bean元件

再在需要的方法前用注解标注為通知方法

@Aspect
@Component
public class AuthAspect {
	

	
	@Before("execution(* com.zzxtit.spring.aop.anno.*.*(..))")
	public void beforeAdvice(JoinPoint jp) {
		System.out.println("===================權限控制=====================");
	}
	
	@After("execution(* com.zzxtit.spring.aop.anno.*.*(..))")
	public void afterAdvice(JoinPoint jp) {
		System.out.println("-----------權限控制後置通知-----------------");
	}
}
           

 重用切入點定義:通過 @Pointcut 注解将一個切入點聲明成簡單的方法. 切入點的方法體通常是空的。其他通知可以通過方法名稱引入該切入點。

/**
	 * 通過pointCut進行切入點的代碼抽離
	 */
	@Pointcut("execution(* com.zzxtit.spring.aop.anno.*.*(..))")
	public void loggerPointCut() {
		
	}
           
//	@Before("execution(* com.zzxtit.spring.aop.anno.*.*(..))")
	@Before("loggerPointCut()")
	public void beforeAdvice(JoinPoint jp) {
		System.out.println("===================權限控制=====================");
	}
           

 若使用 @Order 注解,指定切面的優先級,否則它們的優先級是不确定的,值從0開始,越小優先級越高。

@Order(1)
@Aspect
@Component
public class AuthAspect {
           

在工程中查找jar包中類使用快捷鍵ctrl+shift+T

查找工程中的類使用快捷鍵ctrl+shift+R

繼續閱讀