本篇开始Aop的相关的内容,aop的底层使用到了动态代理的,我们针对一个方法可以配置多个切面,也就实现了多重代理。本篇先不看源码,从开发者的角度观望如何实现多重代理。
一,代理模式
代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问。
代理模式的主要角色如下。
- 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
- 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
在代码中,一般代理会被理解为代码增强,实际上就是在原代码逻辑前后增加一些代码逻辑,而使调用者无感知。
根据代理的创建时期,代理模式分为静态代理和动态代理。
动态代理
- 特点:字节码随用随修改,随用随加载
- 作用:在不修改源码的基础上在运行时动态的对方法进行增强
- 分类:
- 基于接口的动态代理
- 基于子类的动态代理
- 基于接口的动态代理
- 涉及的类:Proxy
- 提供者:JDK官方
- 如何创建代理对象
- 使用Proxy类的
**newProxyInstance()**
- 使用Proxy类的
- 创建代理对象的要求
- 被代理类最少实现一个接口,如果没有则不能使用
**newProxyInstance()**
的参数- ClassLoader:类加载器,用于加载代理对象字节码文件;和被代理对象使用相同的类加载器。
- Class[]:字节码数组,用于让代理对象和被代理对象实现相同方法的。
- InvocationHandler:用于提供增强的代码,他是让我们自定义如何代理,我们一般都是写一个该接口的实现类。
简单的实现
public class Test1 {
@Test
public void test1(){
//被代理类对象要声明为最终的
final Producer producer=new Producer();
//代理对象和被代理类对象要实现同一个接口
IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
producer.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 作用:执行被代理对象的任何接口方法都会经过该方法
* 方法参数的含义
* @param proxy 代理对象的引用
* 1. 可以使用反射获取代理对象的信息(也就是proxy.getClass().getName()。
* 2. 可以将代理对象返回以进行连续调用,这就是proxy存在的目的,因为this并不是代理对象。
* @param method 当前执行的方法
* @param args 当前执行方法所需的参数
* @return 和被代理对象方法相同的返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object value=null;
//获取方法执行的参数
//判断当前方法是不是销售
if ("saleProduct".equals(method.getName())){
Float money= (Float) args[0];
//两个参数:被代理类对象,方法增强的参数
value=method.invoke(producer,money*0.8f);
}
return value;
}
});
proxyProducer.saleProduct(10000f);
}
}
```java package com.es.java1;
/**
一个生产者 */ public class Producer implements IProducer{
/**
- 销售
@param money */ public void saleProduct(float money){ System.out.println(“销售产品,并拿到钱:”+money); }
/**
- 售后
- @param money */ public void afterService(float money){ System.out.println(“提供售后服务,并拿到钱:”+money); } }
/**
对生产厂家要求的接口 */ public interface IProducer {
/**
- 销售
@param money */ public void saleProduct(float money);
/**
- 售后
- @param money
*/
public void afterService(float money);
}
```
2.cglib动态代理
基于子类的动态代理
- 涉及的类:Enhancer ,提供者:第方cglib库
- 如何创建代理对象: 使用Enhancer类中的create方法
- 创建代理对象的要求: 被代理类是最终类
- create方法的参数:
- Class:字节码 :它是用于指定被代理对象的字节码。
- Callback:用于提供增强的代码 :它是让我们写如何代理。我们一般都是些一个该接口的实现类。 我们一般写的都是该接口的子接口实现类:
**MethodInterceptor**
- 简单的实现
/**
* @author yinhuidong
* @createTime 2020-03-02-1:08
*/
public class Test4 {
@Test
public void test() {
final Producer producer = new Producer();
Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的任何方法都会经过该方法
* @param proxy
* @param method
* @param args
* 以上个参数和基于接口的动态代理中invoke方法的参数是一样的
* @param methodProxy :当前执行方法的代理对象
* @return
* @throws Throwable
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//提供增强的代码
Object returnValue = null;
//1.获取方法执行的参数
Float money = (Float) args[0];
//2.判断当前方法是不是销售
if ("saleProduct".equals(method.getName())) {
returnValue = method.invoke(producer, money * 0.8f);
}
return returnValue;
}
});
cglibProducer.saleProduct(12000f);
}
}
二,多重代理
1.基于责任链模式的多重代理
1.1 被代理的方法
```java public interface Animal { void eat(String food);}
public class Cat implements Animal{
@Override public void eat(String food) { System.out.println(“猫吃”+food+”!”); } }
<a name="Iyv5A"></a>
### 1.2封装目标对象的目标方法
```java
public class TargetMethod {
/**
* 目标对象
*/
private Object target;
/**
* 目标方法
*/
private Method method;
/**
* 方法参数
*/
private Object[] args;
public TargetMethod(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
}
1.3 抽象的责任链节点和驱动责任链往下执行的头节点
public abstract class AbstractSlot {
TargetMethod targetMethod;
AbstractSlot next;
abstract Object invoke(TargetMethod targetMethod);
private boolean hasNextSlot() {
return next != null;
}
public Object proceed(TargetMethod targetMethod) throws Exception {
return hasNextSlot() ?
next.invoke(targetMethod) :
targetMethod.getMethod()
.invoke(
targetMethod.getTarget(),
targetMethod.getArgs()
);
}
public AbstractSlot(TargetMethod targetMethod, AbstractSlot next) {
this.targetMethod = targetMethod;
this.next = next;
}
public TargetMethod getTargetMethod() {
return targetMethod;
}
public void setTargetMethod(TargetMethod targetMethod) {
this.targetMethod = targetMethod;
}
public AbstractSlot getNext() {
return next;
}
public void setNext(AbstractSlot next) {
this.next = next;
}
public AbstractSlot() {
}
public static class Head extends AbstractSlot{
@Override
Object invoke(TargetMethod targetMethod) {
return null;
}
}
}
1.4 对方法增强的类
public class JdkDynamic implements InvocationHandler {
Object target ;
AbstractSlot head;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return head.proceed(new TargetMethod(
target,method,args
));
}
public Object getProxy(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
public JdkDynamic(Object target, AbstractSlot head) {
this.target = target;
this.head = head;
}
}
1.5测试类
public class Main {
public static void main(String[] args) {
AbstractSlot.Head head = new AbstractSlot.Head();
AbstractSlot first = new First();
AbstractSlot second=new Second();
first.setNext(second);
head.setNext(first);
JdkDynamic jdkDynamic = new JdkDynamic(new Cat(),head);
Animal proxy = (Animal) jdkDynamic.getProxy();
proxy.eat("事物");
}
private static class First extends AbstractSlot{
@Override
Object invoke(TargetMethod targetMethod) {
Object result = null;
System.out.println("增强逻辑");
try {
result= proceed(targetMethod);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("增强逻辑");
return result;
}
}
private static class Second extends AbstractSlot{
@Override
Object invoke(TargetMethod targetMethod) {
Object result = null;
System.out.println("增强逻辑");
try {
result= proceed(targetMethod);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("增强逻辑");
return result;
}
}
}
2.基于拦截器的多重代理
2.1 拦截器
public interface MyInterceptor {
Object invoke(MyInvocation myInvocation);
}
class One implements MyInterceptor{
@Override
public Object invoke(MyInvocation myInvocation) {
Object result = null;
System.out.println("1");
result=myInvocation.proceed();
System.out.println("4");
return result;
}
}
class Two implements MyInterceptor{
@Override
public Object invoke(MyInvocation myInvocation) {
Object result = null;
System.out.println("2");
result=myInvocation.proceed();
System.out.println("3");
return result;
}
}
2.2 增强器
public interface MyInvocation {
Object proceed();
}
class MyInvocationImpl implements MyInvocation{
List<MyInterceptor> interceptors = new ArrayList<>();
int size =0;
TargetMethod targetMethod;
@Override
public Object proceed() {
try {
return size == interceptors.size()?
targetMethod.getMethod()
.invoke(
targetMethod.getTarget(),
targetMethod.getArgs()
):
interceptors.get(size++)
.invoke(this);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public MyInvocationImpl(List<MyInterceptor> interceptors, TargetMethod targetMethod) {
this.interceptors = interceptors;
this.targetMethod = targetMethod;
}
}
2.3 对方法的增强类
public class JdkProxy implements InvocationHandler {
Object target;
List<MyInterceptor> interceptors = new ArrayList<>();
public void add(MyInterceptor a) {
interceptors.add(a);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return new MyInvocationImpl(
interceptors,
new TargetMethod(
target,
method,
args
)
).proceed();
}
public Object getProxy(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
public JdkProxy(Object target) {
this.target = target;
}
}
2.4 测试类
public class Main {
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy(new Cat());
jdkProxy.add(new One());
jdkProxy.add(new Two());
((Animal) jdkProxy.getProxy()).eat("事务");
}
}
三,AOP相关概念
AOP:全称是 Aspect Oriented Programming 即:面向切面编程。就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
- 作用:
在程序运行期间,不修改源码对已有方法进行增强。 - 优势:
减少重复代码
提高开发效率
维护方便
AOP 相关术语
- Joinpoint(连接点):
所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。 - Pointcut(切入点):
所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。 - Advice(通知/增强):
所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。 - Introduction(引介):
引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。 - Target(目标对象):被代理对象
代理的目标对象。 - Weaving(织入):
是指把增强应用到目标对象来创建新的代理对象的过程。
spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。 - Proxy(代理:
一个类被 AOP 织入增强后,就产生一个结果代理类。 - Aspect(切面):
是切入点和通知(引介的结合)
Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
至此,我们通过两种方式完成了多重代理实现AOP,也简单介绍了两种实现动态代理的方式,和AOP相关的一些概念。下一篇将开始分析注解版Aop源码。