Spring AOP的底层实现原理

Spring的两大核心之一就是AOP,AOP:面向切面编程。在说原理之前,得先知道一些AOP的专业术语。

AOP的专业术语

连接点(JoinPoint):增强执行的位置(增加代码的位置),Spring只支持方法;

切点(PointCut):具体的连接点;一般可能通过一个表达式来描述;

增强(Advice):也称为消息,指的是增加的额外的代码,Spring中,增强除了包含代码外,还包含位置信息;

Spring中一共有四种增强:

MethodBeforeAdvice:前置增强

MethodInterceptor:环绕增强

ThrowsAdvice:异常增强

AfterReturingAdvice:返回值增强

引介(Introduction):特殊的增强,动态为类增加方法

织入(Weaving):将增强加入到目标类的过程,织入分为三种时期

编译器:AspectJ

类加载

运行期:jdk动态代理(实现接口),CGlib(子类,不能用final

目标对象(Target):原始对象

代理对象(Proxy):加入了增强的对象,是生成的;

切面(Aspect):切点+增强


接下来我要说的就是在运行期间织入的两种实现方式

JDK动态代理(实现接口)

  什么是代理模式呢?

  代理模式有三个角色,分别是

抽象角色:接口

目标角色:实现类

代理角色:实现接口(InvocationHandler),并引用目标角色

代理模式与装饰者模式的区别

类图(结构)基本一样,但目的不同,装饰模式的前提是已经所有的类,并进行组装;而

使用代理模式时,我们不能直接访问目标角色或没有权限访问时,可以使用代理模式

 

代理模式分为两种

静态代理:需要为每个目标角色,创建一个对应的代理角色;类的数量会急剧膨胀

动态代理:自动为每个目标角色生成对应的代理角色


接下来就是jdk动态代理的代码:

实现jdk动态代理的前提是所有的目标类都必须要基于一个统一的接口


创建统一的接口

package com.dao;


/**
 * 为目标类定义统一的接口SleepDao
 * @author XuXQ
 *
 */
public interface SleepDao {
	
	public void sleep();


}

定义目标对象

package com.daoImpl;

import com.dao.SleepDao;

/**
 * 目标类
 * @author XuXQ
 *
 */
public class SleepDaoImpl implements SleepDao {

	@Override
	public void sleep() {
		System.out.println("本大人要睡觉了");
	}

}


创建代理角色

package com.handler;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 创建的类得需要实现InvocationHandler,并重写invoke()方法
 * InvocationHandler 是代理实例的调用处理程序 实现的接口
 * 即:MyInvocationHandler 是代理实例的调用处理程序
 * @author XuXQ
 *
 */
public class MyInvoctionHandler implements InvocationHandler {
	Object object=null;//目标对象
	


	public MyInvoctionHandler(Object object) {
		super();
		this.object = object;
	}




	/**
	 * proxy=代理对象
	 * method=被调用方法的方法名
	 * args=被调用方法的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("睡觉前要脱衣服啊");
		Object obj=method.invoke(object, args);//obj为目标对象调用方法的返回值
		System.out.println("睡着了当然得做个美梦啊");
		return obj;
	}


}


编写测试用例
package com.handler;

import static org.junit.Assert.*;

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

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.dao.SleepDao;
import com.daoImpl.SleepDaoImpl;

public class Test1 {

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void test() {
		//目标类必须基于统一的接口
		SleepDao s=new SleepDaoImpl();
		ClassLoader classLoader=s.getClass().getClassLoader();
		MyInvoctionHandler myInvoctionHandler=new MyInvoctionHandler(s);
		
		//Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例  
		SleepDao sd=(SleepDao) Proxy.newProxyInstance(classLoader, s.getClass().getInterfaces(), myInvoctionHandler);
		
		//相当于调用代理角色的Invoke()
		sd.sleep();
	}

}

结果:



由结果可以看到成功的将增强织入到了目标对象中了


CGlib代理


package com.cglibproxy;
/**
 * 和JDK动态代理不同,不需要创建统一的接口
 * @author XuXQ
 *
 */
public class Base {
	public void sleep(){
		System.out.println("本大少要睡觉啦");
	}
}

创建cglib的代理对象

package com.cglibproxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;


//用来生成代理对象
public class CglibProxy implements MethodInterceptor {
	
	public Object getProxy(Object object){
		Enhancer e=new Enhancer();//创建代理对象类
		e.setSuperclass(object.getClass());//声明代理对象的父类是谁(是目标对象)
		e.setCallback(this);//设置回调函数,即调用intercept()
		return e.create();//返回创建的代理对象
	}
	/**
	 * proxy=代理对象,也是目标对象的子类
	 * args=方法参数
	 */
	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy arg3) throws Throwable {
		System.out.println("你个大懒猪,竟然睡觉前不脱衣服,嫌弃o");
		Object object=arg3.invokeSuper(proxy, args);
		System.out.println("起床啦,要不然得迟到了哦");
		return null;
	}

}

编写测试用例

package com.cglibproxy;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;

public class Test {

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@org.junit.Test
	public void test() {
		CglibProxy proxy=new CglibProxy();
		Base base=(Base) proxy.getProxy(new Base());
		base.sleep();
	}

}

结果:



由结果同样可以看到成功的将增强织入到了目标对象中了



总结

当然我们以后写代码都是基于Aspect,直接写注解的,当然这并不代表这我们不需要知道AOP

底层的实现原理,至于注解用的是哪种实现方式,使用配置来解决的,这里就不详解了。

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring AOP底层实现原理主要是基于动态代理。Spring AOP通过使用代理模式,在运行时动态地为目标对象生成一个代理对象,然后通过代理对象来完成对目标对象的方法增强。 具体实现步骤如下: 1. 定义切面类:切面类是一个普通的Java类,用于定义切点和增强逻辑。切点是指确定在何处应用增强逻辑的表达式。增强逻辑是指在切点处插入的具体行为,如日志记录、事务管理等。 2. 配置切面:在Spring配置文件中,通过<aop:aspect>标签配置切面类,并使用<aop:pointcut>标签定义切点表达式。 3. 创建代理对象:在Spring容器启动时,会解析配置文件并扫描所有的Bean对象。当Spring发现某个Bean对象需要进行AOP增强时,会为该对象动态地创建一个代理对象。代理对象可以通过JDK动态代理或者CGLIB动态代理来创建。 4. 方法调用时的增强逻辑:当通过代理对象调用方法时,实际上是调用了代理对象中的方法。在代理对象的方法中,会根据切点表达式判断是否需要插入增强逻辑。如果需要插入增强逻辑,则会在方法的前后或者异常抛出时执行相应的增强操作。 总结起来,Spring AOP底层实现原理是通过动态代理,在运行时为目标对象生成代理对象,并在代理对象中实现对目标对象方法的增强。这个过程是在Spring容器启动时进行的,通过配置文件中的切面定义和切点表达式,确定增强逻辑的插入位置。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值