Aop 简介:
Aop(Aspect Oriented Programming)面向切面编程,是OOP面向对象编程的一种补充将程序中交叉业务(事务,日志)代码提取出来,封装成切面,由AOP容器在适当时机位置将封装成的切面动态的织入到具体业务逻辑中。
AOP不是spring特有的。
应用场合:适用于具有横切逻辑的场合,如事务管理,日志记录,性能检测,异常通知,访问控制等。
作用:不改变原有代码的基础动态添加新的功能。
模块化。
术语:
**连接点(JoinPoint)**程序执行的某个特定位置,如方法调用前,方法调用后,方法抛出异常时,方法调用前后等。
**切入点(PointCut)**定位位置找到需要切入的连接点,即切点。
增强Advice也称为通知 在切点上执行的一段代码用来实现某些功能。
目标对象 Target 将执行增强处理的目标类。
织入(Weaving) 将增强添加到目标类具体切入点的过程。
代理(Proxy) 一个类被织入增强后,会产生一个代理类。
切面 Aspect 切点和增强的组合。
引介 Introduction 也称为引入。
实现原理
代理模式:
概念:为其他对象提供一种代理,以控制对这个对象的访问,起到中介的作用,通过代理对象访问目标对象,可以增强额外的操作,扩展目标对象的功能。
分类:
**静态代理:**代理类是程序员创建或工具生成的,所谓静态代理就是程序运行之前就已经存在代理类的字节码文件。缺点:代理对象需要和目标对象实现相同的接口,如果接口增加方法,目标对象和代理对象都要维护。
动态代理:代理类是程序在运行期间由JVM根据反射等机制动态生成的,自动生成代理类和代理对象,所谓动态就是在程序运行之前不存在代理类的字节码文件。
代理三要素:
一:实现目标类的接口。
二:初始化目标类的实例。
三:交叉业务,要执行的操作。
动态代理:
JDK技术:
proxy.newProxyInstance(
classloader 目标类的类加载器
interfaces 目标类得到接口列表
InvocationHandler 交叉业务逻辑
)
缺点:目标对象必须实现一个或多个接口,如果没有实现接口,则无法使用JDK的动态代理,此时可以使用cglib技术
- cglib技术
- 添加jar包maven依赖
- <dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
- cglib技术,适用于无接口的使用
通过继承实现的cglib技术要
(1):添加jar包
(2):用法:
Enhance.create(
class, 目标类的对象
InvocationHandler 交叉业务逻辑
)
Aop原理
SpringAop 原理就是动态代理
对于实现接口的目标类使用的是jdk动态代理
对于没有实现任何接口的目标类,使用的是cglib的动态代理
代理类是程序在运行期间由JVM根据反射等机制动态生成的自动生成代理类和代理对象。
所谓动态就是指在程序运行前不存在代理类的字节码文件。
AOP基于注解的配置介绍
一:@Component 此注解使用在class上来声明一个Spring组件(Bean), 将其加入到应用上下文中 ,添加到IOC容器中,不区分组件类型。
二:@Aspect 此注解使用在class类上表示这是一个切面
三: @Pointcut定义切点表达式,可以使用within语法,也可以使用execution语法。
例如: @Pointcut("execution(* aop.service.impl.*ServiceImpl.*(..))")
AspectJ表达式
简介:切点表达式,一种表达式,用来定义切点位置。
用法:
within 语法:within(包名.类名) 匹配该类中的所有方法。
execution
匹配特定包中的特定类中特定返回值类型的特定参数的特定方法。
语法:execution(表达式)
表达式:返回值类型 包名.类名.方法名(参数类型)
通配符:和…
四:@Before 此注解表示的前置通知在方法执行之前执行。
五:@AfterReturning 此注解表示的是后置通知在方法执行之后执行该方法。
六: @AfterThrowing 此注解表示的是异常通知,在方法执行的时候出现异常时执行。
七:@Around*此注解表示的是环绕通知,在方法执行前后都会执行,该通知而用于做性能的监测,比如方法执行的时间统计。
八: contxt:aspectj-autoproxy/ 表示自动创建注解并织入
使用aop注解开发的小案例进一步了解。
配置通知类并基于注解实现的通知(增强)此处根据自己需要实现通知
package aop.advice;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import sun.awt.SunHints;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* package_name:aop.advice
*
* @author:徐亚远 Date:2020/2/21 14:09
* 项目名:springDemo01
* Description:TODO
* Version: 1.0
**/
@Component
//表示这是一个切面
@Aspect
public class AnnotationAdvice {
//定义切点表达式
@Pointcut("execution(* aop.service.impl.*ServiceImpl.*(..))")
public void pt() {
}
@Before("pt()")
public void begoreAdvice(JoinPoint joinPoint) {
//签名
Signature signature = joinPoint.getSignature();
//方法名
String methodName = signature.getName();
//转换为方法签名,本质上是方法签名
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
//参数
Object[] args = joinPoint.getArgs();
//目标类
Object target = joinPoint.getThis();
System.out.println("前置通知: " + "methodName: " + methodName + " " + "args:" + Arrays.toString(args) + " " +
"target: " + target);
}
@AfterReturning(value = "pt()", returning = "value")
public void afterAdvice(JoinPoint joinPoint, Object value) {
//签名
Signature signature = joinPoint.getSignature();
//方法名
String methodName = signature.getName();
//转换为方法签名,本质上是方法签名
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
//参数
Object[] args = joinPoint.getArgs();
//目标类
Object target = joinPoint.getThis();
System.out.println("后置通知: " + "methodName: " + methodName + " " + "args:" + Arrays.toString(args) + " " +
"target: " +
"" + target);
}
@AfterThrowing(value = "pt()", throwing = "e")
public void throwAdvice(JoinPoint joinPoint, Exception e) {
//签名
Signature signature = joinPoint.getSignature();
//方法名
String methodName = signature.getName();
//转换为方法签名,本质上是方法签名
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
//参数
Object[] args = joinPoint.getArgs();
//目标类
Object target = joinPoint.getThis();
System.out.println("异常通知: " + "methodName: " + methodName + " " + "args:" + Arrays.toString(args) + " " +
"target: " +
"" + target);
}
@Around("pt()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint){
Long startTime = System.currentTimeMillis();
Object proceed = null;
try {
System.out.println("开启事务:");
proceed = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("回滚事务:");
return "出错";
}
Long endTime = System.currentTimeMillis();
System.out.println("方法执行时间:"+(endTime-startTime)+"ms");
return proceed;
}
}
书写登录的接口:
package aop.service;
/**
* package_name:com.anno.service
*
* @author:徐亚远 Date:2020/2/20 17:19
* 项目名:springDemo01
* Description:TODO
* Version: 1.0
**/
public interface UserService {
/**
* @Author : 徐亚远
* @Date : 2020/2/21 14:08
* @Description :
* @param password
* @param username
*/
void login(String username, String password);
}
实现登录接口。
package aop.service.impl;
import aop.service.UserService;
import org.springframework.stereotype.Service;
/**
* package_name:com.anno.service.impl
*
* @author:徐亚远 Date:2020/2/20 17:19
* 项目名:springDemo01
* Description:TODO
* Version: 1.0
**/
@Service()
public class UserServiceImpl implements UserService {
/**
* @param username
* @param password
* @Author : 徐亚远
* @Date : 2020/2/21 14:08
* @Description :
*/
@Override
public void login(String username, String password) {
int i = 5/0;
System.out.println("loginUserServiceImpl登录方法执行:" + username + " " + password);
}
}
配置配置文件(spring.xmll)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:contxt="http://www.springframework.org/schema/aop"
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">
<!--扫包把使用注解的实体类配置到IOC容器中,交给容器管理-->
<context:component-scan base-package="aop.service.impl"/>
<context:component-scan base-package="aop.advice"/>
<!--自动创建代理并织入切面
proxy-target-class=""默认false 表示使用jdk动态代理,true表示使用cglib动态代理 使用cglib要加入依赖-->
<contxt:aspectj-autoproxy/>
</beans>
书写测试类:
package aop;
import aop.service.UserService;
import aop.service.impl.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* package_name:aop
*
* @author:徐亚远 Date:2020/2/21 14:16
* 项目名:springDemo01
* Description:TODO
* Version: 1.0
**/
public class controller {
public static void main(String [] args){
ApplicationContext ac = new ClassPathXmlApplicationContext("aop/spring.xml");
UserService userService = (UserService) ac.getBean("userServiceImpl");
userService.login("12","123" );
System.out.println(userService.getClass());
}
}
测试结果如图: