动态代理与AOP
1. 代理的分类:
静态代理:每个代理类只能为一个接口服务
动态代理:可以通过一个代理类完成全部的代理功能(由JVM生成实现一系列接口的代理类,即:生成实现接口的类的代理)
2. 动态代理:
在Java中要想实现动态代理机制,需要 java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 类的支持
java.lang.reflect.InvocationHandler 接口的定义如下:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
Object proxy:被代理的对象
Method method:要调用的方法
Object[] args:方法调用时传递的参数
注意:并不是对象的所有方法均通过代理来完成,对如继承自Object的方法,只将hashCode()、equals()、toString()转交给InvocationHandler来处理。
可以通过Proxy中的getProxyClass()或newProxyInstance()方法获取代理
其中newProxyInstance()方法定义如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
ClassLoader loader:类加载器
Class<?>[] interfaces:要实现的接口
InvocationHandler h:InvocationHandler子类的实例对象
下面来实现动态代理:
首先定义接口:
1 public interface Sourceable {
2 void function();
3 }
然后定义实现类:
1 public class Source implements Sourceable {
2
3 @Override
4 public void function() {
5 System.out.println("function");
6 }
7 }
定义工具类:
1 import java.lang.reflect.Constructor;
2 import java.lang.reflect.InvocationHandler;
3 import java.lang.reflect.Method;
4 import java.lang.reflect.Proxy;
5
6 public class SourceableProxyUtil {
7 private Sourceable source;
8
9 public SourceableProxyUtil(Sourceable source) {
10 super();
11 this.source = source;
12 }
13
14 public Sourceable getProxy() throws Exception {
15 Class<Sourceable> clazzSource = (Class<Sourceable>) Proxy
16 .getProxyClass(source.getClass().getClassLoader(), source
17 .getClass().getInterfaces());
18 Constructor<Sourceable> constructor = clazzSource
19 .getConstructor(InvocationHandler.class); // 没有无参构造函数
20
21 return constructor.newInstance(new InvocationHandler() {
22
23 @Override
24 public Object invoke(Object proxy, Method method, Object[] args)
25 throws Throwable {
26 System.out.println("before");
27 Object retVal = method.invoke(source, args);
28 System.out.println("after");
29 return retVal;
30 }
31 });
32 }
33 }
但是,使用getProxyClass()方式过于复杂,改用newProxyInstance():
1 import java.lang.reflect.Constructor;
2 import java.lang.reflect.InvocationHandler;
3 import java.lang.reflect.Method;
4 import java.lang.reflect.Proxy;
5
6 public class SourceableProxyUtil {
7 private Sourceable source;
8
9 public SourceableProxyUtil(Sourceable source) {
10 super();
11 this.source = source;
12 }
13
14 public Sourceable getProxy() throws Exception {
15 return (Sourceable)Proxy.newProxyInstance(source.getClass().getClassLoader(),
16 source.getClass().getInterfaces(), new InvocationHandler() {
17
18 @Override
19 public Object invoke(Object proxy, Method method,
20 Object[] args) throws Throwable {
21 System.out.println("before");
22 Object retVal = method.invoke(source, args);
23 System.out.println("after");
24 return retVal;
25 }
26 });
27 }
28 }
测试代码:
1 public class Main {
2
3 public static void main(String[] args) throws Exception {
4 Sourceable source = new Source();
5 Sourceable proxy = new SourceableProxyUtil(source).getProxy();
6 proxy.function();
7 }
8 }
测试结果:
before
function
after
可以看出,代理类能够正常使用。
但是上述方式只能用于生成Sourceable接口的代理类,可以进一步将其抽象得到通用的代理类生成工具:
1 import java.lang.reflect.InvocationHandler;
2 import java.lang.reflect.Method;
3 import java.lang.reflect.Proxy;
4
5 public final class ProxyUtil {
6 public static Object getProxy(final Object target) throws Exception {
7 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
8 target.getClass().getInterfaces(), new InvocationHandler() {
9
10 @Override
11 public Object invoke(Object proxy, Method method,
12 Object[] args) throws Throwable {
13 System.out.println("before");
14 Object retVal = method.invoke(target, args);
15 System.out.println("after");
16 return retVal;
17 }
18 });
19 }
20 }
这样,无论任何类型的对象都可以通过此种方法获得相应的代理对象。此时,测试代码如下:
1 public class Main {
2
3 public static void main(String[] args) throws Exception {
4 // TODO Auto-generated method stub
5 Sourceable proxy = (Sourceable)ProxyUtil.getProxy(new Source());
6 proxy.function();
7 }
8 }
3. 抽取切面:
将上述代码中的目标方法执行前后的操作进一步地抽象,将其抽取为切面。将切面代码进行封装得到通告。
定义通告接口:
1 public interface Advice {
2 void before();
3 void after();
4 }
改写工具类:
1 import java.lang.reflect.InvocationHandler;
2 import java.lang.reflect.Method;
3 import java.lang.reflect.Proxy;
4
5 public final class ProxyUtil {
6 public static Object getProxy(final Object target, final Advice advice) throws Exception {
7 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
8 target.getClass().getInterfaces(), new InvocationHandler() {
9
10 @Override
11 public Object invoke(Object proxy, Method method,
12 Object[] args) throws Throwable {
13 advice.before();
14 Object retVal = method.invoke(target, args);
15 advice.after();
16 return retVal;
17 }
18 });
19 }
20 }
此时的测试代码为:
1 public class Main {
2
3 public static void main(String[] args) throws Exception {
4 Sourceable proxy = (Sourceable)ProxyUtil.getProxy(new Source(), new Advice() {
5
6 @Override
7 public void before() {
8 // TODO Auto-generated method stub
9 System.out.println("before");
10 }
11
12 @Override
13 public void after() {
14 // TODO Auto-generated method stub
15 System.out.println("after");
16 }
17 });
18 proxy.function();
19 }
20 }
此种方式更具有普遍适用性,无论对于任意类型都可以产生相对应的代理对象,同时可以自定义所要进行的操作(通过通告)。
在整个过程中需要手动写的只有通告Advice
4. AOP编程:
AOP(Aspect-Oriented Programming)可以通过代理方式完成诸如:安全控制、事务管理、性能统计、日志记录、错误处理...等功能。
在实际过程中,更多是通过getter/setter方式传递target与advice的:
1 import java.lang.reflect.InvocationHandler;
2 import java.lang.reflect.Method;
3 import java.lang.reflect.Proxy;
4
5 public class ProxyFactoryBean {
6
7 private Object target;
8 private Advice advice;
9
10
11 public Object getTarget() {
12 return target;
13 }
14
15
16 public void setTarget(Object target) {
17 this.target = target;
18 }
19
20
21 public Advice getAdvice() {
22 return advice;
23 }
24
25
26 public void setAdvice(Advice advice) {
27 this.advice = advice;
28 }
29
30
31 public Object getProxy() {
32
33 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
34 target.getClass().getInterfaces(), new InvocationHandler() {
35
36 @Override
37 public Object invoke(Object proxy, Method method,
38 Object[] args) throws Throwable {
39 advice.before();
40 Object retVal = method.invoke(target, args);
41 advice.after();
42 return retVal;
43 }
44 });
45 };
46 }
通过AOP的方式可以在运行时动态地将代码切入到类的指定方法、指定位置上。
Spring框架的核心即是IoC和AOP。
posted on 2016-11-04 21:33 Joshua_AW 阅读(1812) 评论(0) 编辑 收藏 举报