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 术语

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值