***springAOP使用代理模式实现,代理模式可以将我们的业务代码,和扩展功能进行分 离,由代理对象去做扩展的方法,业务代码无需做很大的改动,springAOP就是对代理模式的一种实现,在调用目标方法对象之前由代理对象去做一些别的功能
动态代理例子
java.lang.reflect反射包下,Proxy.newProxyInstance()静态方法可以创建代理对象
以及InvocationHandler 代理实例的调用处理程序 实现的接口可以查看api学习
package com.springboot.proxyFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.springframework.beans.factory.annotation.Autowired;
import com.springboot.mapp.Ainmal;
import com.springboot.mapp.Cat;
//代理工厂
//@Component
public class ProxyFactory {
// 目标对象
@Autowired
private Cat cat;//Cat实现了Ainmal接口
public ProxyFactory(Cat cat) {
this.cat=cat;
}
//创建代理对象
@SuppressWarnings("unchecked")
public Ainmal getProxyObject(CarAdd carAdd) {//传入需要扩展功能的类,在调用目标方法之前或之后进行扩展
//
return (Ainmal)Proxy.newProxyInstance(
//目标对象的类加载器
cat.getClass().getClassLoader(),
//目标对象实现的接口数组,程序会在运行时生成代理类,代理类会实现给定的接口
cat.getClass().getInterfaces(),
//代理对象需要调用的处理器,代理对象调用方法,都由处理器的invoke方法处理,调用目标对象中的方法
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//carAdd.before();扩展方法
Object rest=method.invoke(cat, args);
//carAdd.after();扩展方法
return rest;
}
});
}
}
AOP核心概念
2、切面(aspect)
类是对物体特征的抽象,切面就是对横切关注点的抽象
3、连接点(joinpoint)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut)
对连接点进行拦截的定义。execution(* com.springboot.controller.*.*(..))"你要拦截哪里的方法。。。
5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
6、目标对象
代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
POM文件中引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
切面类
package com.springboot.proxyFactory;
import java.lang.reflect.Modifier;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Component
@Aspect//切面
public class CarAdd {
/**
切点表达式:包下的所有类中的所有方法都会生成代理类,..表示任意参数。
springAOP,在程序运行过程中,如果运行到切点匹配的(表达式时),
jvm会动态的生成代理类,如果拦截到的类有实现接口,那么使用jdk动态代理,
否则使用cglbi子类继承的方式进行生成代理类,类为finli不能被代理会报错,
目标方法为静态,或者finli类型,aop的扩展功能不会被执行
*/
@Pointcut("execution(* com.springboot.controller.*.*(..))")
public void qieDian() {}
//前置通知
//JoinPoint:封装了切点表达式中,匹配到的方法信息
@Before("qieDian()")
public void before(JoinPoint joinPoint) {
System.out.println(joinPoint);
System.out.println("获取目标方法的方法名"+joinPoint.getSignature().getName());
System.out.println("目标方法所属类的简单类名:"+joinPoint.getSignature().getDeclaringType().getSimpleName());
System.out.println("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
System.out.println("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
System.out.println("获取被代理的对象"+joinPoint.getTarget());
System.out.println("获取代理对象"+joinPoint.getThis());
//获取request对象
ServletRequestAttributes sqa=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request= sqa.getRequest();
String requestURI = request.getRequestURI();
String remoteAddr = request.getRemoteAddr();
String requestMethod = request.getMethod();
String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("请求url=" + requestURI + ",客户端ip=" + remoteAddr + ",请求方式=" + requestMethod + ",请求的类名=" + declaringTypeName + ",方法名=" + methodName + ",入参=" + args);
System.out.println("猫吃饭之前");
}
}