springAOP详解


来源参考,b站狂神说: https://www.bilibili.com/video/BV1WE411d7Dv?spm_id_from=333.999.0.0

静态代理

为什么要学习代理模式,因为AOP的底层机制就是动态代理!我们先从静态代理聊起。

静态代理角色分析

  • 抽象角色 : 一般使用接口或者抽象类来实现
  • 真实角色 : 被代理的角色
  • 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
  • 客户 : 使用代理角色来进行一些操作 .

案例

抽象角色

//抽象角色:租房
public interface Rent {
	public void rent();
}

真实角色

//真实角色: 房东,房东要出租房子
public class Host implements Rent{
	public void rent() {
		System.out.println("房屋出租");
	}
}

代理角色

public class Proxy implements Rent {
	private Host host;
	public Proxy() { }
	public Proxy(Host host) {
		this.host = host;
	}
	//租房
	public void rent(){
		seeHouse();
		host.rent();
		fare();
	}
	//看房
	public void seeHouse(){
		System.out.println("带房客看房");
	}
	//收中介费
	public void fare(){
		System.out.println("收中介费");
	}
}

客户

//客户类,一般客户都会去找代理!
public class Client {
public static void main(String[] args) {
		//房东要租房
		Host host = new Host();
		//中介帮助房东
		Proxy proxy = new Proxy(host);
		//你去找中介!
		proxy.rent();
	}
}

分析: 在这个过程中,你直接接触的就是中介,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子通过代理,这就是所谓的代理模式,程序源自于生活,所以学编程的人,一般能够更加抽象的看待生活中发生的事情。

优点:

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便

缺点 :

  • 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .

我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !

动态代理

  • 动态代理的角色和静态代理的一样 .
  • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
  • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
    • 基于接口的动态代理----JDK动态代理
    • 基于类的动态代理–cglib
    • javasist 来生成动态代理 . 百度一下javasist

spring使用的是什么动态代理?

spring中使用到两种动态代理(JDK和cglib)。spring会判断目标有没有实现接口,如果有就使用jdk动态代理;没有则使用cglib动态代理。也可以通过设置,强制使用cglib动态代理。详细源码分析

JDK动态代理与cglib动态代理的实现原来及区别

原理:

  • jdk动态代理与cglib动态代理的思想都是通过字节码去生成一个类,然后对原来的类进行功能增强
  • JDK动态代理是实现InvocationHandler接口,重写invoke(),通过反射的方式去调用目标类的代码。JDK的代理是针对接口的,所以被代理的对象必须要实现接口
  • cglib实现MethodInterceptor接口,重写intercept(),对目标类生成子类覆盖他的方法,由于采用的是继承的方式,故目标类不可以被final修饰

区别:

  • jdk动态代理要求目标类必须实现接口
  • 在代理类时,jdk动态代理生成一个文件;cglib会生成三个文件,生成代理类时jdk会更快
  • jdk动态代理调用方法是通过反射,cglib是通过fastclass机制,通过枚举、索引去定位到方法。在jdk1.8之前cglib会更快,1.8之后jdk会更快

JDK动态代理(案例)

jdk与cglib动态代理的代码都大同小异,这里使用jdk来实现动态代理

  1. 抽象角色
//抽象角色:租房
public interface Rent {
	public void rent();
}
  1. 真实角色
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
	public void rent() {
		System.out.println("房屋出租");
	}
}
  1. 代理角色
public class ProxyInvocationHandler implements InvocationHandler {

	private Rent rent;
	
	public void setRent(Rent rent) {
		this.rent = rent;
	}
	
	//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
	public Object getProxy(){
		return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
	}
	
	// proxy : 代理类 method : 代理类的调用处理程序的方法对象.
	// 处理代理实例上的方法调用并返回结果
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		seeHouse();
		//核心:本质利用反射实现!
		Object result = method.invoke(rent, args);
		fare();
		return result;
	}
	
	//看房
	public void seeHouse(){
		System.out.println("带房客看房");
	}
	
	//收中介费
	public void fare(){
		System.out.println("收中介费");
	}
}
  1. 调用
//租客
public class Client {
	public static void main(String[] args) {
		//真实角色
		Host host = new Host();
		//代理实例的调用处理程序
		ProxyInvocationHandler pih = new ProxyInvocationHandler();
		pih.setRent(host); //将真实角色放置进去!
		Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
		proxy.rent();
	}
}

核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!

AOP

什么是AOP

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现
程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的
一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使
得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

Aop在Spring中的作用

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要
  • 关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知 执行的 “地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。

在这里插入图片描述

使用Spring实现Aop

导入一个依赖包

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.9.4</version>
</dependency>

首先编写我们的业务接口和实现类

public interface UserService {
	public void add();
	public void delete();
	public void update();
	public void search();
}

public class UserServiceImpl implements UserService{
	@Override
	public void add() {
		System.out.println("增加用户");
	}
	@Override
	public void delete() {
		System.out.println("删除用户");
	}
	@Override
	public void update() {
		System.out.println("更新用户");
	}
	@Override
	public void search() {
		System.out.println("查询用户");
	}
}
第一种方式

通过 Spring API 实现
编写增强类,一个前置增强 一个后置增强

public class Log implements MethodBeforeAdvice {
	//method : 要执行的目标对象的方法
	//objects : 被调用的方法的参数
	//Object : 目标对象
	@Override
	public void before(Method method, Object[] objects, Object o) throws Throwable {
		System.out.println( o.getClass().getName() + "的" + method.getName()+ "方法被执行了");
	}
}
public class AfterLog implements AfterReturningAdvice {
	//returnValue 返回值
	//method被调用的方法
	//args 被调用的方法的对象的参数
	//target 被调用的目标对象
	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		System.out.println
		("执行了" + target.getClass().getName()+ "的" + method.getName()+ "方法," + "返回值:"+returnValue);
	}
}

最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束

<?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: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/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">
		
	<!--注册bean-->
	<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
	<bean id="log" class="com.kuang.log.Log"/>
	<bean id="afterLog" class="com.kuang.log.AfterLog"/>
	<!--aop的配置-->
	<aop:config>
		<!--切入点 expression:表达式匹配要执行的方法-->
		<aop:pointcut id="pointcut" expression="execution(*com.kuang.service.UserServiceImpl.*(..))"/>
		<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
		<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
		<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
	</aop:config>
</beans>
第二种方式

写我们自己的一个切入类

public class DiyPointcut {
	public void before(){
		System.out.println("---------方法执行前---------");
	}
	public void after(){
		System.out.println("---------方法执行后---------");
	}
}

去spring中配置

<!--第二种方式自定义实现-->
<!--注册bean-->
<bean id="diy" class="com.kuang.config.DiyPointcut"/>

<!--aop的配置-->
<aop:config>
	<!--第二种方式:使用AOP的标签实现-->
	<aop:aspect ref="diy">
		<aop:pointcut id="diyPonitcut" expression="execution(*com.kuang.service.UserServiceImpl.*(..))"/>
		<aop:before pointcut-ref="diyPonitcut" method="before"/>
		<aop:after pointcut-ref="diyPonitcut" method="after"/>
	</aop:aspect>
</aop:config>
第三种方式(推荐)
package com.kuang.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointcut {

	@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
	
	public void before(){
		System.out.println("---------方法执行前---------");
	}
	
	@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
	public void after(){
		System.out.println("---------方法执行后---------");
	}
	
	@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
	public void around(ProceedingJoinPoint jp) throws Throwable {
		System.out.println("环绕前");
		System.out.println("签名:"+jp.getSignature());
		//执行目标方法proceed
		Object proceed = jp.proceed();
		System.out.println("环绕后");
		System.out.println(proceed);
	}
}

注意:需要注册bean,支持注解配置

Spring AOP(面向切面编程)是Spring框架中的一个模块,用于提供横切关注点(Cross-Cutting Concerns)的支持。横切关注点是与应用程序的核心业务逻辑无关的功能,例如日志记录、性能统计、事务管理等。 在Spring AOP中,通过定义切面(Aspect)来捕获横切关注点,并将其应用到目标对象的方法中。切面由切点(Pointcut)和通知(Advice)组成。切点定义了在何处应用通知,通知则定义了在切点处执行的操作。 Spring AOP支持以下几种类型的通知: 1. 前置通知(Before Advice):在目标方法执行之前执行的通知。 2. 后置通知(After Advice):在目标方法执行之后执行的通知,不管方法是否抛出异常。 3. 返回通知(After Returning Advice):在目标方法成功执行并返回结果后执行的通知。 4. 异常通知(After Throwing Advice):在目标方法抛出异常后执行的通知。 5. 环绕通知(Around Advice):围绕目标方法执行的通知,可以在方法调用前后执行自定义操作。 除了通知,Spring AOP还支持引入(Introduction)和切点表达式(Pointcut Expression)等功能。引入允许为目标对象添加新的接口和实现,而切点表达式则允许开发人员定义切点的匹配规则。 要在Spring应用程序中使用AOP,需要进行以下步骤: 1. 引入Spring AOP的依赖。 2. 配置AOP代理。 3. 定义切面和通知。 4. 配置切点和通知之间的关系。 总之,Spring AOP提供了一种便捷的方式来处理横切关注点,使得开发人员可以将关注点与核心业务逻辑分离,提高代码的可维护性和可重用性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值