详解Aop

2022-10-27 15:49:08 浏览数 (2)

上一篇文章中,介绍了java中的代理模式,这篇文章就来了解一下代理模式的扩展也就是Spring中的Aop,Aop是什么呢?惯例我们还是来看一下360百科上给我们的详细介绍(这里应该翻译官方文档的,但是目前能力有限,还不快速翻阅Spring的官方文档)在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 百科里面讲到的AOP是OOP的延续,我个人并不赞成这句话,了解java的人都知道,OOP就是面向对象编程,是java开发中,非常重要的思想,用过Spring框架的也都了解,当我们想在不修改一个业务逻辑的源代码的前提下想对这个业务进行一下功能上的拓展,我们都会优先想到Spring框架中的AOP技术,AOP是一种技术,是一种解决问题的手段,和思想是不能完全划等号的。下面就来介绍一下在实际开发中,代码中会出现的API以及变量声明,也就是AOP中的一些基本概念

代码语言:javascript复制
Spring aop中的基本概念
  • 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。 个人理解:连接点就是你想要增强的业务的方法,调用的目标层中每一个方法都是一个连接点
  • 切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。 个人理解:切入点就是目标层中你想要增强的方法,就是一个切入点。
  • 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现。 个人理解:拿javaee中经典的三层架构来举个例子,表现层(web)想要调用业务层(service),业务层中所有的方法都会成为切入点,我们想对这些方法进行增强,问题来了,用于增强切入点的这些代码我们要写到那里嘞?表现层?nonono!表现层是后台与用户交互的地方,也是沃我们接收请求的地方,不能在这里,不能在这里。业务层?nonono业务层是我们书写业务逻辑的地方,不能耦合不能耦合。持久层?持久层是我们与数据库交互的地方,一堆与数据库无关的代码怎么能放到这里呢。这也不能放,那也不能放,到底要放到哪里?我们可以新建一个类哦,这个类不属于三层架构中的任何一层,他的作用有点类似于web三大技术之一的过滤器(filter),想象一下,我们用一把刀把一块豆腐一起为二,刀放到那里不要动,这把刀就是所谓的切面
  • 通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。 个人理解:通知就是切面中用于增强功能的代码,也就是切面中写有增强功能的代码。
  • 目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。 个人理解:被调用的类对象。 下面用注解形式自己实现一个aop的小案例 基于注解的AOP案例

模拟一个注册用户的小案例

web层代码

代码语言:javascript复制
@Controller
public class UserServlet {

	@Autowired
	UserService userService = null;
	
	public void addUser() {
		
		userService.addUser();
	}
}

service层代码

代码语言:javascript复制
package com.jmy.service;

public interface UserService {

	public void addUser();
}
代码语言:javascript复制
package com.jmy.service;

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("添加联系人成功!");
		try {
			Thread.sleep();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

切面

代码语言:javascript复制
package com.jmy.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/*
 * 记录业务执行时间
 */
@Component
@Aspect
public class UseTimeAspect {

	// 配置环绕通知
	@Around("execution(void com.jmy.service.*.*(..))")
	public void around(ProceedingJoinPoint pjp) throws Throwable {
		long begin = System.currentTimeMillis();
		Object object = pjp.proceed();
		long end = System.currentTimeMillis();
		long useTime = end - begin;
		System.out.println("###调用[" pjp.getTarget() "]的[" pjp.getSignature().getName() "]方法,用时[" useTime "]毫秒###");

	}
}

测试代码

代码语言:javascript复制
package com.jmy.test;

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

import com.jmy.web.UserServlet;

public class Test01 {
	
	@Test
	public void test01() {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserServlet userServlet = (UserServlet) context.getBean("userServlet");
		userServlet.addUser();
		((ClassPathXmlApplicationContext)context).close();
	}

}

运行结果

代码语言:javascript复制
添加联系人成功!
###调用[com.jmy.service.UserServiceImpl@3b69e7d1]的[addUser]方法,用时[]毫秒###

contextApplication.xml

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

	<!-- 配置包扫描 -->     
	<context:component-scan base-package="com.jmy.service"></context:component-scan>
	<context:component-scan base-package="com.jmy.web"></context:component-scan>  
	<context:component-scan base-package="com.jmy.aspect"></context:component-scan>
	<!-- 配置注解 -->
	<context:annotation-config></context:annotation-config>    
	<!-- 配置注解aop -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
html

好啦…就这样。

0 人点赞