在学习AOP之前,我们得先学习一下代理模式,以帮助我们理解AOP思想。
代理模式是AOP的实现思想。所以这里有必要先了解代理模式原理。
首先,按照字面意思,代理模式就是找个人来帮自己做事,这样做有两个原因:
在代理模式中,我们有三种角色:
这里要明白,我们设置目标对象和代理对象的公共接口的目的是为了统一目标对象和代理对象间的行为。
比如,如果我的目标对象中有一个删除数据的功能,需要另一个代理对象来对该功能进行增强。那么首先要保证——目标对象和代理对象中都有这个删除数据的功能(或方法),才能让目标对象把这个任务交给代理对象去做。而这一点,可以通过设置一个两者共用的接口来完成。
以图的方式表示如下:

可以看出,由代理对象来实际对接用户完成实际任务,但对于用户而言只会觉得调用的是目标对象中的delete()功能.
而在具体的代码实现中,我们有两种方式:
静态代理就是由我们自己手动的创建目标对象、代理对象、目标对象和代理对象公共接口。
下面以一个案例说明如何编写。
假设我们已经有了Service层实现类及其接口——OrderService、OrderServiceImpl
其代码如下:
OrderService
package com.powernode.mall.service;
/**
* 订单接口
**/
public interface OrderService {
/**
* 生成订单
*/
void generate();
/**
* 查看订单详情
*/
void detail();
/**
* 修改订单
*/
void modify();
}
OrederServiceImpl
package com.powernode.mall.service.impl;
import com.powernode.mall.service.OrderService;
public class OrderServiceImpl implements OrderService {
@Override
public void generate() {
try {
Thread.sleep(1234);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已生成");
}
@Override
public void detail() {
try {
Thread.sleep(2541);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单信息如下:******");
}
@Override
public void modify() {
try {
Thread.sleep(1010);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已修改");
}
}
该service功能正常,但是现在需要对其功能进行增强——需要计算每个方法的执行时间。
直接的想法可能是去修改实现类中的代码,但是这样违反了OCP原则,我们不应该为了增加新功能而去修改已经完成的正常运行的代码。
所以我们会考虑使用代理模式进行工作增强。
在这种情况下,我们可以分析出如下关系:
OrderService——目标对象和代理对象公共接口
OrderServiceImpl——目标对象
所以我们还需要手动为创建代理对象:
package com.powernode.mall.service;
public class OrderServiceProxy implements OrderService{ // 代理对象
// 目标对象
private OrderService orderService;
// 通过构造方法将目标对象传递给代理对象
public OrderServiceProxy(OrderService orderService) {
this.orderService = orderService;
}
@Override
public void generate() {
long begin = System.currentTimeMillis();
// 执行目标对象的目标方法
orderService.generate();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end - begin)+"毫秒");
}
@Override
public void detail() {
long begin = System.currentTimeMillis();
// 执行目标对象的目标方法
orderService.detail();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end - begin)+"毫秒");
}
@Override
public void modify() {
long begin = System.currentTimeMillis();
// 执行目标对象的目标方法
orderService.modify();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end - begin)+"毫秒");
}
}
代理对象中会引入目标对象作为属性,然后在调用目标对象前后进行额外的功能补强。
这么一来,我们在实际使用时,调用的是代理对象中的方法,就能够使用原有的功能以及新增的功能了。
动态代理中我们不用自己手动创建代理对象,而是由在代码运行时动态的创建代理对象。
能够动态生成类的技术常见的有:JDK动态代理、CGLIB动态代理。
由jdk反射包中的Proxy类来完成,但是只能代理接口。
下面我们使用JDK动态代理完成前面静态代理中相同的案例。
首先,我们的OrderService接口和OrderServiceImpl的代码不变:
OrderService
package com.powernode.mall.service;
public interface OrderService {
/**
* 生成订单
*/
void generate();
/**
* 查看订单详情
*/
void detail();
/**
* 修改订单
*/
void modify();
}
OrderServiceImpl
package com.powernode.mall.service.impl;
import com.powernode.mall.service.OrderService;
public class OrderServiceImpl implements OrderService {
@Override
public void generate() {
try {
Thread.sleep(1234);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已生成");
}
@Override
public void detail() {
try {
Thread.sleep(2541);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单信息如下:******");
}
@Override
public void modify() {
try {
Thread.sleep(1010);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订单已修改");
}
}
这里我们不需要手动创建一个类作为代理对象,而是使用Proxy类来创建代理对象
public class Client {
public static void main(String[] args) {
// 创建目标对象
OrderService orderService = new OrderServiceImpl();
// 创建代理对象
OrderService o = (OrderService) Proxy.newProxyInstance(orderService.getClass().getClassLoader(),
orderService.getClass().getInterfaces(), new TimeInvocationHandle());
// 调用代理方法
o.generate();
}
}
从上面的代码可知,我们使用newProxyInstance()方法来动态的创建代理对象。
所以我们先介绍一下这个方法。
以下为源码:

发现该方法需要三个参数:
前面说过newProxyInstance()的第三个参数需要的InvocationHandler接口是我们写增强代码的地方,那么现在我们需要手动创建一个InvocationHandler的实现类,并在里面编写额外的功能代码。
创建出的实现类基本结构如下:
package org.example.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeInvocationHandle implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke执行");
return null;
}
}
其中invoke()方法就是我们的“额外功能”,该方法会在我们执行了目标对象中的方法后自动执行。
那么又有问题了,我们如何决定这些“额外功能”哪些在原方法前执行,哪些在原方法之后执行呢?
这些就需要了解一下invoke()方法的各个参数了:
上面的参数中我们可以获取到调用“目标方法”所需的Method类对象、参数、但是我们还要拿到目标对象。所以我们还需要在这个InvocationHandler实现类中设置一个目标对象类型的属性,然后我们可以使用有参构造器进行属性赋值。
于是我们可以在invoke()方法中调用原方法(“目标方法”),并自由决定在其前后添加额外的功能代码,最终我们的实现类如下:
package org.example.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimerInvocationHandler implements InvocationHandler {
// 目标对象
private Object target;
// 通过构造方法来传目标对象
public TimerInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 目标执行之前增强。
long begin = System.currentTimeMillis();
// 调用目标对象的目标方法
Object retValue = method.invoke(target, args);
// 目标执行之后增强。
long end = System.currentTimeMillis();
System.out.println("(end - begin)+"毫秒");
// 一定要记得返回哦。
return retValue;
}
}
需要注意的是,如果原方法是有返回值的,那么我们实现类的invoke方法中也要记得设置返回值。
并且我们既然要用构造方法为属性赋值,则客户端的代码创建对象时也要把目标对象传入:
public class Client {
public static void main(String[] args) {
// 创建目标对象
OrderService orderService = new OrderServiceImpl();
// 创建代理对象
OrderService o = (OrderService) Proxy.newProxyInstance(orderService.getClass().getClassLoader(),
orderService.getClass().getInterfaces(), new TimeInvocationHandle(orderService));
// 调用代理方法
o.generate();
}
}

最后,我们使用Proxy创建出来的对象任意调用一个目标方法都会添加上额外功能的代码。

是一个开源项目,它既可以代理接口,又可以代理类,底层是通过继承的方式实现的(所以需要代理的类不能被final修饰),底层有一个小而快的字节码处理框架ASM。
我们简单学习了代理模式,这是我们学习AOP的前提。