基础框架 Spring AOP切面
基础框架 Spring AOP切面
一、概念
- 什么是aop
AOP就是面向切面编程,就是不通过修改代码的方式,在主干功能的某个类的方法执行前后添加新的功能。 - 为什么要用aop
AOP面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被称为为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。
二、aop原理
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
①JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
②如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式实现动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
aop两种代理模式案例
三、常见术语
- 连接点
类里面那些方法可以被增强,这些方法称为连接点。 - 切入点
实际被真正增强的方法,称为切入点。 通知(增强)
实际增强逻辑部分称为通知(增强)- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
切面
把通知应用到切入点的过程。
四、案例
- Spring框架aop操作一般都是基于AspectJ实现
AspectJ不是spring组成部分,独立aop框架,一般AspectJ和spring框架结合使用,进行aop操作。 基于AspectJ实现aop操作方式
- 基于xml配置文件实现
- 基于注解实现
引入依赖
- 切入点表达式
(1)切入点表达式的作用:知道对哪个类的那个方法增强。
(2)语法结构:
execution([权限修饰符] [返回类型] [类全路径] [方法名称] (参数列表))
例1:对com.spring.dao.BookDao类的add增强
execution(* com.spring.dao.BookDao.add(. .))
例2:对com.spring.dao.BookDao类的所有方法增强
execution(* com.spring.dao.BookDao.*(. .))
例3:对com.spring.dao包的所有类的所有方法增强
execution(* com.spring.dao..(. .))
验证
aop实现的三种方式
(1)xml配置
(2)注解方式
(3)AspectJ配置package com.spring5.aopanno;
import org.springframework.stereotype.Component;
/ 用户 @author zrj @date 2020/12/20 * @since V1.0 /
@Component
public class User {/** * 定义新增方法 */
public void add() {
System.out.println( "【UserDao】执行add方法..." );
}
}
package com.spring5.aopanno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/ User增强类 Component:标注bean Aspect :生成代理对象 Order:有多个不同类型的增强的时候,设置优先级 @author zrj @date 2020/12/20 @since V1.0 /
@Component
@Aspect
@Order(3)
public class UserProxy {/** * 相同切入点抽取 */
@Pointcut(value = "execution(* com.spring5.aopanno.User.add(..))")
public void pointDemo() {
}
/** * 前置通知 * * @Before注解表示作为前置通知 */
@Before(value = "pointDemo()")
public void before() {
System.out.println( "【前置通知】Before........." );
}
/** * 后置通知(返回通知) */
@AfterReturning(value = "execution(* com.spring5.aopanno.User.add(..))")
public void afterReturning() {
System.out.println( "【后置通知】AfterReturning........." );
}
/** * 最终通知 */
@After(value = "execution(* com.spring5.aopanno.User.add(..))")
public void after() {
System.out.println( "【最终通知】After........." );
}
/** * 异常通知 */
@AfterThrowing(value = "execution(* com.spring5.aopanno.User.add(..))")
public void afterThrowing() {
System.out.println( "【异常通知】AfterThrowing........." );
}
/** * 环绕通知 */
@Around(value = "execution(* com.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println( "【环绕之前】Around........." );
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println( "【环绕之后】Around........." );
}
}
package com.spring5.aopxml;
/ 书 @author zrj @date 2020/12/20 * @since V1.0 /
public class Book {public void buy() {
System.out.println( "【购买方法】buy............." );
}
}
package com.spring5.aopxml;
import org.aspectj.lang.ProceedingJoinPoint;
/ 书增强类 @author zrj @date 2020/12/20 * @since V1.0 /
public class BookProxy {/** * 前置通知 * * @Before注解表示作为前置通知 */
public void before() {
System.out.println( "【前置通知】Before........." );
}
/** * 后置通知(返回通知) */
public void afterReturning() {
System.out.println( "【后置通知】AfterReturning........." );
}
/** * 最终通知 */
public void after() {
System.out.println( "【最终通知】After........." );
}
/** * 异常通知 */
public void afterThrowing() {
System.out.println( "【异常通知】AfterThrowing........." );
}
/** * 环绕通知 */
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println( "【环绕之前】Around........." );
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println( "【环绕之后】Around........." );
}
}
package com.spring5.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;/* 3.注解方式实现aop操作 */
@Configuration
@ComponentScan(basePackages = { “com.spring5”})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}<?xml version=”1.0” encoding=”UTF-8”?>
package com.spring5.aopanno;
import com.spring5.aopxml.Book;
import com.spring5.config.ConfigAop;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/ @author zrj @date 2020/12/20 * @since V1.0 /
public class SpringAopTest {/** * xml配置方式操作aop */
@Test
public void springAopXmlTest() {
System.out.println( "-----xml配置方式操作aop-----" );
// 加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext( "bean2.xml" );
// 获取对象
User user = context.getBean( "user", User.class );
user.add();
}
/** * 注解方式实现aop */
@Test
public void springAopConfigTest() {
System.out.println( "-----注解方式实现aop-----" );
// 加载配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext( ConfigAop.class );
// 获取对象
User user = applicationContext.getBean( "user", User.class );
user.add();
}
/** * AspectJ配置文件方式 */
@Test
public void springAopAspectJXmlTest() {
System.out.println( "-----AspectJ配置文件方式-----" );
// 加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext( "bean2.xml" );
// 获取对象
Book book = context.getBean( "book", Book.class );
book.buy();
}
}
还没有评论,来说两句吧...