一、AOP相关的概念
1.什么是AOP的技术?
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构;AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范;通过预编译方式或者运行期动态代理实现程序功能的统一维护的一种技术;AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(事务管理、安全检查、缓存)。
2.AOP的优势
运行期间,不修改源代码的情况下对已有的方法进行增强
- 减少重复的代码
- 提供开发的效率
- 维护方便
3.AOP的底层原理
- JDK的动态代理技术
为接口创建代理类的字节码文件
使用ClassLoader将字节码文件加载到JVM
创建代理类实例对象,执行对象的目标方法
- cglib代理技术
为类生成代理对象,被代理类有没有接口都无所谓,底层是生成子类,继承被代理类
4.AOP相关的术语
①Joinpoint(连接点) 类里面有哪些方法可以增强这些方法称为连接点
②Pointcut(切入点) – 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
③Advice(通知/增强)-- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
前置通知:在一个方法执行之前执行
后置通知:在一个方法执行之后执行
环绕通知:在一个方法执行前后都要执行
异常通知:在一个方法发生异常时执行
最终通知:类似于finally,一个方法有没有执行完都要执行
④Aspect(切面)-- 是 切入点+通知 的结合,以后咱们自己来编写和配置的
二、AOP技术
1.Spring实现AOP
创建maven项目,编写pow.xml,导入坐标依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
编写接口UserService.java
public interface UserService {
public void add();
public void delete();
public void update();
public void search();
}
编写实现类UserServiceImpl.java
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加用户");
}
public void delete() {
System.out.println("删除用户");
}
public void update() {
System.out.println("更新用户");
}
public void search() {
System.out.println("查询用户");
}
}
在方法执行前要执行的操作
public class Log implements MethodBeforeAdvice {
//method : 要执行的目标对象的方法
//objects : 被调用的方法的参数
//Object : 目标对象
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 被调用的目标对象s
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + target.getClass().getName()
+"的"+method.getName()+"方法,"
+"返回值:"+returnValue);
}
}
配置bean
<bean id="log" class="com.spring.aop1.Log"/>
<bean id="afterlog" class="com.spring.aop1.AfterLog"/>
<bean id="userservice" class="com.spring.aop1.UserServiceImpl"/>
配置切入点
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.spring.aop1.UserServiceImpl.*(..))"/>
<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
测试方法
@Test
public void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean("userservice",UserService.class);
userService.add();
}
结果:
com.spring.aop1.UserServiceImpl的add方法被执行了
增加用户
com.spring.aop1.UserServiceImpl的add方法被执行了,返回值:null
2.自定义方法实现AOP
自定义方法
public class Log {
public void beforeLog() {
System.out.println("在方法执行前执行");
}
public void afterLog() {
System.out.println("在方法执行后执行");
}
}
配置bean
<bean id="log" class="com.spring.aop2.Log"/>
<bean id="userservice2" class="com.spring.aop2.UserServiceImpl"/>
配置实现AOP
<aop:config>
<!--第二种方式:使用AOP的标签实现-->
<aop:aspect ref="log">
<aop:pointcut id="diyPonitcut" expression="execution(* com.spring.aop2.UserServiceImpl.*(..))"/>
<!-- before关键字,代表在执行前执行beforeLog方法-->
<aop:before pointcut-ref="diyPonitcut" method="beforeLog"/>
<!-- after关键字,代表在执行前执行afterLog方法-->
<aop:after pointcut-ref="diyPonitcut" method="afterLog"/>
</aop:aspect>
</aop:config>
测试方法
public class MyTest2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean("userservice2",UserService.class);
userService.add();
}
}
结果:
在方法执行前执行
增加用户
在方法执行后执行
3.注解实现
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.spring.aop3.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.spring.aop3.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.spring.aop3.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,并增加支持注解的配置
<bean id="userservice3" class="com.spring.aop3.UserServiceImpl"/>
<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.zhang.aop3.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
测试方法
public class MyTest3 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean("userservice3",UserService.class);
userService.add();
}
}
结果:
环绕前
签名:void com.spring.aop3.UserService.add()-—-------方法执行前–——-----
增加用户
环绕后null
---------方法拉行后---------