spring aop

本文没有去探寻源码,只是根据现象去推理一下:

1 定义切面类:

package main.daoImpl;

import org.aspectj.lang.JoinPoint;
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.aspectj.lang.annotation.Pointcut;

@Aspect
public class LogAnnotationAspect {
	
	@Pointcut("execution(* main.daoImpl.*.*(..))")
	public void allMethod() {}

	@Before("allMethod()")
	public void before(JoinPoint jp) {
		System.out.println("Args:" + jp.getArgs());
		System.out.println("Kind:" + jp.getKind());
		System.out.println("Signature:" + jp.getSignature());
		System.out.println("Target:" + jp.getTarget());
		System.out.println("this:" + jp.getThis());
		System.out.println("正在进行权限校验!before...");
		System.out.println(jp.getSignature().getName());
		if (jp.getSignature().getName().equals("login")) {
		}
	}
	
	@After("allMethod()")
	public void after() {
		System.out.println("结束调用!after...");
	}
	
	@Around("allMethod()")
	public void around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("环绕! around...");
		pjp.proceed();
	}
	
	@AfterReturning(pointcut="allMethod()", returning="rvt")
	public void afterReturning(Object rvt) {
		System.out.println("rrrrrrrrrrrrrrrrrrrrrrrr     " + rvt + "    rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr");
	}
	
	@AfterThrowing("allMethod()")
	public void afterThrow() {
		System.out.println("after throwing...");
	}
	
}

 2 目标类

   (1)目标类不实现接口:

     

package main.daoImpl;

import main.dao.TestDao;

public class TestDaoImpl {

	public String test() throws Exception {
		System.out.println("test main...");
		return "test data!";
	}
	

   测试代码:

  

	@Test
	public void test() {
		try {
			TestDaoImpl testDaoImpl = (TestDaoImpl)context.getBean("testDaoImpl");
			System.out.println("current class: " + testDaoImpl.getClass().getName());
			System.out.println("parent class or interface : " + testDaoImpl.getClass().getSuperclass().getName());
			System.out.println("is aop proxy: " + AopUtils.isAopProxy(testDaoImpl));
			System.out.println("is cglib proxy: " + AopUtils.isCglibProxy(testDaoImpl));
			System.out.println("is jdk proxy: " + AopUtils.isJdkDynamicProxy(testDaoImpl));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			
		}
	}

    测试结果:

   current class: main.daoImpl.TestDaoImpl$$EnhancerByCGLIB$$a6cb1969
   parent class or interface : main.daoImpl.TestDaoImpl
  is aop proxy: true
  is cglib proxy: true
  is jdk proxy: false

  从获取的testDaoImpl的class名称为:main.daoImpl.TestDaoImpl$$EnhancerByCGLIB$$a6cb1969,熟悉cglib动态代理的应该知道,这类名称符合cglib动态代理生成类的命名,而且testDaoImpl父类的名称为:main.daoImpl.TestDaoImpl,也就是testDaoImpl继承了类main.daoImpl.TestDaoImpl,此恰恰符合cglib动态代理的特征;所以当目标类没有实现接口时,spring aop使用cglib动态代理生成一个代理类,把切面类

中配置的通知织入到动态代理类内,代理类调用方法时,就会触发通知。

 

    (2)目标类实现接口:

package main.daoImpl;

import main.dao.TestDao;

public class TestDaoImpl implements TestDao {

	public String test() throws Exception {
		System.out.println("test main...");
		return "test data!";
	}
	
}

    切面类和上面一致,测试代码为:

	@Test
	public void test() {
		try {
			TestDao testDaoImpl = (TestDao)context.getBean("testDaoImpl");
			System.out.println("current class: " + testDaoImpl.getClass().getName());
			System.out.println("parent class or interface : " + testDaoImpl.getClass().getSuperclass().getName());
			System.out.println("is aop proxy: " + AopUtils.isAopProxy(testDaoImpl));
			System.out.println("is cglib proxy: " + AopUtils.isCglibProxy(testDaoImpl));
			System.out.println("is jdk proxy: " + AopUtils.isJdkDynamicProxy(testDaoImpl));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			
		}
	}

 测试结果:

current class: $Proxy13
parent class or interface : java.lang.reflect.Proxy
is aop proxy: true
is cglib proxy: false
is jdk proxy: true

testDaoImpl类名为$Proxy13, 继承了 java.lang.reflect.Proxy,由此可知当目标类实现接口的时候,spring aop 使用jdk的动态代理生成动态代理类把通知织入到动态代理类内

 

从上面的代码可知,spring aop的总体逻辑为,根据目标类是否实现接口来选择使用jdk还是使用cglib来生成代理类,把通知中的逻辑织入到代理类中

 

###Spring AOP 的概念 AOP(Aspect-Oriented Programming)即面向切面编程,是一种编程范式,旨在通过分离横切关注点来提高模块化程度。在 Spring 框架中,AOP 被广泛用于实现诸如日志记录、事务管理、安全性等通用功能,这些功能通常与业务逻辑无关但又需要在多个地方重复使用。 Spring AOP 主要是基于 AspectJ 实现的,尽管 AspectJ 是一个独立的 AOP 框架,并不是 Spring 的组成部分,但它通常与 Spring 一起使用以提供更强大的 AOP 功能[^1]。Spring AOP 支持两种方式来定义切面:基于 XML 配置文件的方式和基于注解的方式。 ###Spring AOP 的原理 Spring AOP 使用运行时代理来实现 AOP 功能,这意味着它会在运行时动态生成代理对象。对于实现了接口的类,Spring AOP 默认使用 JDK 动态代理;而对于没有实现接口的类,则会使用 CGLIB 代理[^4]。这种方式允许在不修改原始代码的情况下向程序中添加新的行为。 织入(Weaving)是将增强(advice)应用到目标对象的过程,Spring AOP 在运行时进行织入操作[^3]。当创建了代理对象后,所有对目标对象方法的调用都会被拦截,并且可以插入额外的操作,比如在方法执行前后做一些处理。 ###Spring AOP 的使用教程 要开始使用 Spring AOP,首先需要确保项目中包含了必要的依赖。如果使用 Maven 构建工具,可以在 `pom.xml` 文件中加入如下依赖: ```xml <!-- 引入aop依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 一旦添加了依赖并刷新了 Maven 项目,就可以开始编写切面了。下面是一个简单的例子,展示如何使用注解来定义一个切面: ```java import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Method " + joinPoint.getSignature().getName() + " is called."); } } ``` 在这个示例中,`LoggingAspect` 类被标记为 `@Aspect` 和 `@Component` 注解,这样 Spring 就能识别这是一个切面组件。`@Before` 注解指定了在哪些方法上应用前置通知(before advice),这里的表达式表示匹配 `com.example.service` 包下所有的方法。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值