先说结论,感兴趣的往下看:
静态代理就是常用的聚合方式,这种方式用来代理很简单,但是扩展性较差,如果需要代理多个方法,需要在代理类里把多个方法都写出来,而动态代理就没这种问题。

JDK代理是基于接口实现的,原理其实是动态生成一个子类去实现这个接口,所以需要代理的对象必须实现某个接口,并且需要代理的方法必须是接口里定义过的抽象方法。

CGLIB代理是基于类去实现的,当需要代理的类无法使用JDK代理的时候就可以使用CGLIB代理,另外需要代理的类必须不能使用final修饰,因为CGLIB实质上是通过继承需要代理的类,然后在子类中重写方法来实现的。

静态代理

定义一个AbstractExample接口

1
2
3
public interface AbstractExample {
void run();
}

创建一个Example类实现接口

1
2
3
4
5
6
7
8
9
10
11
/**
* 需要被代理的类
*/
public class Example implements AbstractExample{

@Override
public void run() {
// 为了演示,这边输出一些内容
System.out.println("Example run()");
}
}

正常情况下,我们不代理的话是直接创建Example的实例化对象然后直接调用run方法的。这边需要代理,静态代理的类如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 静态代理类
*/
public class StaticProxy {

private final Example example = new Example();

public StaticProxy() {
}

public void run(){
System.out.println("静态代理1");
example.run();
System.out.println("静态代理2");
}
}

从代码可以看到这边定义了一个和Example同名同参同返回类型的方法,是为了方便调用者更清楚知道应该使用哪个代理方法。如果这边把这些改了并且Example有多个方法的话,那调用者就不确定是不是代理的Example的无返回值的run方法。

我们在实例化使用的时候,也是创建的代理对象,通过代理对象来调用想要调的方法:

1
2
3
4
5
6
7
8
9
public class ProxyTest {

public static void main(String[] args) {
// 创建的时候是创建代理对象,而不是代理前的对象
StaticProxy proxy = new StaticProxy();

proxy.run();
}
}

控制台输出如下:

1
2
3
静态代理1
Example run()
静态代理2

可以看到,除了输出Example run()之外,前后还加上了静态代理类的输出内容。很明显静态代理的使用方式就是我们常用的聚合方式。

动态代理:JDK代理

同样需要AbstractExample和Example来演示

1
2
3
public interface AbstractExample {
void run();
}
1
2
3
4
5
6
7
8
9
10
11
/**
* 需要被代理的类
*/
public class Example implements AbstractExample{

@Override
public void run() {
// 为了演示,这边输出一些内容
System.out.println("Example run()");
}
}

定义JDK代理类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.lang.reflect.Proxy;

/**
* JDK动态代理
*/
public class JDKProxy {

private Example example = new Example();

public AbstractExample getProxy(){
AbstractExample proxyInstance = (AbstractExample) Proxy.newProxyInstance(example.getClass().getClassLoader(), example.getClass().getInterfaces(), (proxy, method, args) -> {

System.out.println("JDK动态代理1");
Object object = method.invoke(example, args);
System.out.println("JDK动态代理2");

// 本方法需要有返回值,由于void是不需要返回值的所以object其实是null
return object;
});

return proxyInstance;
}
}

JDK动态代理需要使用到java.lang.reflect下的Proxy类,调用其newProxyInstance方法获取代理对象。newProxyInstance方法需要传递3个参数,下面贴下源码分析下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
* Returns a proxy instance for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
* <p>
* <a id="restrictions">{@code IllegalArgumentException} will be thrown
* if any of the following restrictions is violated:</a>
* <ul>
* <li>All of {@code Class} objects in the given {@code interfaces} array
* must represent {@linkplain Class#isHidden() non-hidden} and
* {@linkplain Class#isSealed() non-sealed} interfaces,
* not classes or primitive types.
*
* <li>No two elements in the {@code interfaces} array may
* refer to identical {@code Class} objects.
*
* <li>All of the interface types must be visible by name through the
* specified class loader. In other words, for class loader
* {@code cl} and every interface {@code i}, the following
* expression must be true:<p>
* {@code Class.forName(i.getName(), false, cl) == i}
*
* <li>All of the types referenced by all
* public method signatures of the specified interfaces
* and those inherited by their superinterfaces
* must be visible by name through the specified class loader.
*
* <li>All non-public interfaces must be in the same package
* and module, defined by the specified class loader and
* the module of the non-public interfaces can access all of
* the interface types; otherwise, it would not be possible for
* the proxy class to implement all of the interfaces,
* regardless of what package it is defined in.
*
* <li>For any set of member methods of the specified interfaces
* that have the same signature:
* <ul>
* <li>If the return type of any of the methods is a primitive
* type or void, then all of the methods must have that same
* return type.
* <li>Otherwise, one of the methods must have a return type that
* is assignable to all of the return types of the rest of the
* methods.
* </ul>
*
* <li>The resulting proxy class must not exceed any limits imposed
* on classes by the virtual machine. For example, the VM may limit
* the number of interfaces that a class may implement to 65535; in
* that case, the size of the {@code interfaces} array must not
* exceed 65535.
* </ul>
*
* <p>Note that the order of the specified proxy interfaces is
* significant: two requests for a proxy class with the same combination
* of interfaces but in a different order will result in two distinct
* proxy classes.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the <a href="#restrictions">
* restrictions</a> on the parameters are violated
* @throws SecurityException if a security manager, <em>s</em>, is present
* and any of the following conditions is met:
* <ul>
* <li> the given {@code loader} is {@code null} and
* the caller's class loader is not {@code null} and the
* invocation of {@link SecurityManager#checkPermission
* s.checkPermission} with
* {@code RuntimePermission("getClassLoader")} permission
* denies access;</li>
* <li> for each proxy interface, {@code intf},
* the caller's class loader is not the same as or an
* ancestor of the class loader for {@code intf} and
* invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to {@code intf};</li>
* <li> any of the given proxy interfaces is non-public and the
* caller class is not in the same {@linkplain Package runtime package}
* as the non-public interface and the invocation of
* {@link SecurityManager#checkPermission s.checkPermission} with
* {@code ReflectPermission("newProxyInPackage.{package name}")}
* permission denies access.</li>
* </ul>
* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}, or
* if the invocation handler, {@code h}, is
* {@code null}
*
* @see <a href="#membership">Package and Module Membership of Proxy Class</a>
* @revised 9
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
Objects.requireNonNull(h);

@SuppressWarnings("removal")
final Class<?> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();

/*
* Look up or generate the designated proxy class and its constructor.
*/
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);

return newProxyInstance(caller, cons, h);
}

第一个参数是需要我们传类加载器,第二个是interfaces,可以通过Class的getInterfaces来实现,第三个参数搜索传递一个InvocationHandler对象:

分析一下源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/

package java.lang.reflect;

import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;

import java.lang.invoke.MethodHandle;
import java.util.Objects;

/**
* {@code InvocationHandler} is the interface implemented by
* the <i>invocation handler</i> of a proxy instance.
*
* <p>Each proxy instance has an associated invocation handler.
* When a method is invoked on a proxy instance, the method
* invocation is encoded and dispatched to the {@code invoke}
* method of its invocation handler.
*
* @author Peter Jones
* @see Proxy
* @since 1.3
*/
public interface InvocationHandler {

/**
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
*
* @param proxy the proxy instance that the method was invoked on
*
* @param method the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance. The declaring
* class of the {@code Method} object will be the interface that
* the method was declared in, which may be a superinterface of the
* proxy interface that the proxy class inherits the method through.
*
* @param args an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* or {@code null} if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* {@code java.lang.Integer} or {@code java.lang.Boolean}.
*
* @return the value to return from the method invocation on the
* proxy instance. If the declared return type of the interface
* method is a primitive type, then the value returned by
* this method must be an instance of the corresponding primitive
* wrapper class; otherwise, it must be a type assignable to the
* declared return type. If the value returned by this method is
* {@code null} and the interface method's return type is
* primitive, then a {@code NullPointerException} will be
* thrown by the method invocation on the proxy instance. If the
* value returned by this method is otherwise not compatible with
* the interface method's declared return type as described above,
* a {@code ClassCastException} will be thrown by the method
* invocation on the proxy instance.
*
* @throws Throwable the exception to throw from the method
* invocation on the proxy instance. The exception's type must be
* assignable either to any of the exception types declared in the
* {@code throws} clause of the interface method or to the
* unchecked exception types {@code java.lang.RuntimeException}
* or {@code java.lang.Error}. If a checked exception is
* thrown by this method that is not assignable to any of the
* exception types declared in the {@code throws} clause of
* the interface method, then an
* {@link UndeclaredThrowableException} containing the
* exception that was thrown by this method will be thrown by the
* method invocation on the proxy instance.
*
* @see UndeclaredThrowableException
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;

/**
* Invokes the specified default method on the given {@code proxy} instance with
* the given parameters. The given {@code method} must be a default method
* declared in a proxy interface of the {@code proxy}'s class or inherited
* from its superinterface directly or indirectly.
* <p>
* Invoking this method behaves as if {@code invokespecial} instruction executed
* from the proxy class, targeting the default method in a proxy interface.
* This is equivalent to the invocation:
* {@code X.super.m(A* a)} where {@code X} is a proxy interface and the call to
* {@code X.super::m(A*)} is resolved to the given {@code method}.
* <p>
* Examples: interface {@code A} and {@code B} both declare a default
* implementation of method {@code m}. Interface {@code C} extends {@code A}
* and inherits the default method {@code m} from its superinterface {@code A}.
*
* <blockquote><pre>{@code
* interface A {
* default T m(A a) { return t1; }
* }
* interface B {
* default T m(A a) { return t2; }
* }
* interface C extends A {}
* }</pre></blockquote>
*
* The following creates a proxy instance that implements {@code A}
* and invokes the default method {@code A::m}.
*
* <blockquote><pre>{@code
* Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { A.class },
* (o, m, params) -> {
* if (m.isDefault()) {
* // if it's a default method, invoke it
* return InvocationHandler.invokeDefault(o, m, params);
* }
* });
* }</pre></blockquote>
*
* If a proxy instance implements both {@code A} and {@code B}, both
* of which provides the default implementation of method {@code m},
* the invocation handler can dispatch the method invocation to
* {@code A::m} or {@code B::m} via the {@code invokeDefault} method.
* For example, the following code delegates the method invocation
* to {@code B::m}.
*
* <blockquote><pre>{@code
* Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { A.class, B.class },
* (o, m, params) -> {
* if (m.getName().equals("m")) {
* // invoke B::m instead of A::m
* Method bMethod = B.class.getMethod(m.getName(), m.getParameterTypes());
* return InvocationHandler.invokeDefault(o, bMethod, params);
* }
* });
* }</pre></blockquote>
*
* If a proxy instance implements {@code C} that inherits the default
* method {@code m} from its superinterface {@code A}, then
* the interface method invocation on {@code "m"} is dispatched to
* the invocation handler's {@link #invoke(Object, Method, Object[]) invoke}
* method with the {@code Method} object argument representing the
* default method {@code A::m}.
*
* <blockquote><pre>{@code
* Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { C.class },
* (o, m, params) -> {
* if (m.isDefault()) {
* // behaves as if calling C.super.m(params)
* return InvocationHandler.invokeDefault(o, m, params);
* }
* });
* }</pre></blockquote>
*
* The invocation of method {@code "m"} on this {@code proxy} will behave
* as if {@code C.super::m} is called and that is resolved to invoking
* {@code A::m}.
* <p>
* Adding a default method, or changing a method from abstract to default
* may cause an exception if an existing code attempts to call {@code invokeDefault}
* to invoke a default method.
*
* For example, if {@code C} is modified to implement a default method
* {@code m}:
*
* <blockquote><pre>{@code
* interface C extends A {
* default T m(A a) { return t3; }
* }
* }</pre></blockquote>
*
* The code above that creates proxy instance {@code proxy} with
* the modified {@code C} will run with no exception and it will result in
* calling {@code C::m} instead of {@code A::m}.
* <p>
* The following is another example that creates a proxy instance of {@code C}
* and the invocation handler calls the {@code invokeDefault} method
* to invoke {@code A::m}:
*
* <blockquote><pre>{@code
* C c = (C) Proxy.newProxyInstance(loader, new Class<?>[] { C.class },
* (o, m, params) -> {
* if (m.getName().equals("m")) {
* // IllegalArgumentException thrown as {@code A::m} is not a method
* // inherited from its proxy interface C
* Method aMethod = A.class.getMethod(m.getName(), m.getParameterTypes());
* return InvocationHandler.invokeDefault(o, aMethod params);
* }
* });
* c.m(...);
* }</pre></blockquote>
*
* The above code runs successfully with the old version of {@code C} and
* {@code A::m} is invoked. When running with the new version of {@code C},
* the above code will fail with {@code IllegalArgumentException} because
* {@code C} overrides the implementation of the same method and
* {@code A::m} is not accessible by a proxy instance.
*
* @apiNote
* The {@code proxy} parameter is of type {@code Object} rather than {@code Proxy}
* to make it easy for {@link InvocationHandler#invoke(Object, Method, Object[])
* InvocationHandler::invoke} implementation to call directly without the need
* of casting.
*
* @param proxy the {@code Proxy} instance on which the default method to be invoked
* @param method the {@code Method} instance corresponding to a default method
* declared in a proxy interface of the proxy class or inherited
* from its superinterface directly or indirectly
* @param args the parameters used for the method invocation; can be {@code null}
* if the number of formal parameters required by the method is zero.
* @return the value returned from the method invocation
*
* @throws IllegalArgumentException if any of the following conditions is {@code true}:
* <ul>
* <li>{@code proxy} is not {@linkplain Proxy#isProxyClass(Class)
* a proxy instance}; or</li>
* <li>the given {@code method} is not a default method declared
* in a proxy interface of the proxy class and not inherited from
* any of its superinterfaces; or</li>
* <li>the given {@code method} is overridden directly or indirectly by
* the proxy interfaces and the method reference to the named
* method never resolves to the given {@code method}; or</li>
* <li>the length of the given {@code args} array does not match the
* number of parameters of the method to be invoked; or</li>
* <li>any of the {@code args} elements fails the unboxing
* conversion if the corresponding method parameter type is
* a primitive type; or if, after possible unboxing, any of the
* {@code args} elements cannot be assigned to the corresponding
* method parameter type.</li>
* </ul>
* @throws IllegalAccessException if the declaring class of the specified
* default method is inaccessible to the caller class
* @throws NullPointerException if {@code proxy} or {@code method} is {@code null}
* @throws Throwable anything thrown by the default method

* @since 16
* @jvms 5.4.3. Method Resolution
*/
@CallerSensitive
public static Object invokeDefault(Object proxy, Method method, Object... args)
throws Throwable {
Objects.requireNonNull(proxy);
Objects.requireNonNull(method);

// verify that the object is actually a proxy instance
if (!Proxy.isProxyClass(proxy.getClass())) {
throw new IllegalArgumentException("'proxy' is not a proxy instance");
}
if (!method.isDefault()) {
throw new IllegalArgumentException("\"" + method + "\" is not a default method");
}
@SuppressWarnings("unchecked")
Class<? extends Proxy> proxyClass = (Class<? extends Proxy>)proxy.getClass();

Class<?> intf = method.getDeclaringClass();
// access check on the default method
method.checkAccess(Reflection.getCallerClass(), intf, proxyClass, method.getModifiers());

MethodHandle mh = Proxy.defaultMethodHandle(proxyClass, method);
// invoke the super method
try {
// the args array can be null if the number of formal parameters required by
// the method is zero (consistent with Method::invoke)
Object[] params = args != null ? args : Proxy.EMPTY_ARGS;
return mh.invokeExact(proxy, params);
} catch (ClassCastException | NullPointerException e) {
throw new IllegalArgumentException(e.getMessage(), e);
} catch (Proxy.InvocationException e) {
// unwrap and throw the exception thrown by the default method
throw e.getCause();
}
}
}

可以看到InvocationHandler是一个接口,并且只有两个方法:invoke和invokeDefault,并且invokeDefault是已经有了方法体的,显然不是我们需要自定义代理的对象,那就只剩下invoke方法需要我们去实现了。所以Proxy.newProxyInstance的第三个参数需要传递实现InvocationHandler重写invoke后的实现类对象。为了方便,其时可以不用定义一个新的类去实现InvocationHandler接口,只需要创建一个匿名类即可,这样更为简洁:

可以使用下列方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public AbstractExample getProxy5(){
AbstractExample proxyInstance = (AbstractExample) Proxy.newProxyInstance(example.getClass().getClassLoader(), example.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("JDK动态代理1");
Object object = method.invoke(example, args);
System.out.println("JDK动态代理2");

// 本方法需要有返回值,由于void是不需要返回值的所以object其实是null
return object;
}
});

return proxyInstance;
}

另外,JDK8开始是有Lambda表达式这一新特性的,对于一个接口,有且仅有一个接口的时候,可以使用Lambda表达式来简写实现。下面是简写后的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
public AbstractExample getProxy(){
AbstractExample proxyInstance = (AbstractExample) Proxy.newProxyInstance(example.getClass().getClassLoader(), example.getClass().getInterfaces(), (proxy, method, args) -> {

System.out.println("JDK动态代理1");
Object object = method.invoke(example, args);
System.out.println("JDK动态代理2");

// 本方法需要有返回值,由于void是不需要返回值的所以object其实是null
return object;
});

return proxyInstance;
}

我在上面JDKProxy类中使用的也是这种写法。

下面测试一下效果,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class ProxyTest {

public static void main(String[] args) {
// 创建代理类
JDKProxy jdkProxy = new JDKProxy();

// 获取代理对象
AbstractExample proxy = jdkProxy.getProxy();
// 调用run方法
proxy.run();
}
}

控制台输出如下:

1
2
3
JDK动态代理1
Example run()
JDK动态代理2

可以看到输出Example run()的前后加上了我们代理的输出。

动态代理:CGLIB代理

有信心的朋友可能已经发现,JDK实现动态代理的时候,需要传递类的interfaces对象,也就是说必须要有接口,那如果一个类并没有实现其他接口,并且需要代理,这种场合应该怎么做呢?

此时就需要使用到CGLIB代理了。

首先需要在pom.xml文件中导入cglib的maven依赖:

1
2
3
4
5
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>

如果不会使用maven的朋友可以上网搜索cglib的jar包下载然后设定依赖即可。

下面同样是使用到了Example类,但是我们的情况是没有AbstractExample这个接口了。

1
2
3
4
5
6
7
8
9
10
/**
* 需要被代理的类
*/
public class Example{

public void run() {
// 为了演示,这边输出一句话
System.out.println("Example run()");
}
}

下面为了方便直接贴上代理代码,然后分析下代码的含义;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
* CGLIB代理
*/
public class CGProxy implements MethodInterceptor {

public Example getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Example.class);
enhancer.setCallback(this);
Example example = (Example) enhancer.create();
return example;
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB代理");
methodProxy.invokeSuper(o, objects);
return null;
}
}

首先创建Enhancer对象,然后调用setSuperclass方法,传入需要代理的类。setCallback方法是设置回调对象,也就是代理时会调用的对象,这边直接传this,然后需要实现MethodInterceptor接口里的intercept方法。只有实现了这个方法回调才能成功,我们在这边写一句输出,到时候输出看效果。然后【methodProxy.invokeSuper(o, objects);】代表是调代理对象的superClass的方法,这里也说明了为什么上面需要通过setSuperclass设置Superclass,如果没设的话是调用失败的。然后这里需要把对象和参数集合传进去,就能够调用对应的方法了。

通过setCallback设置完回调函数并实现了MethodInterceptor接口的intercept之后,可以使用enhancer的create方法创建代理对象,并且可以转成我们需要代理的对象的类型,也就是Example,到这一步就是代理好了,return出去供外部调用。

下面是测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
* CGLIB代理
*/
public class CGProxy implements MethodInterceptor {

public Example getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Example.class);
enhancer.setCallback(this);
Example example = (Example) enhancer.create();
return example;
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB代理1");
methodProxy.invokeSuper(o, objects);
System.out.println("CGLIB代理2");
return null;
}
}

直接使用对象调相应的方法,效果如下:

1
2
3
CGLIB代理1
Example run()
CGLIB代理2

可以发现Example run()的前后都被加上了我们想输出的内容,代理成功。其实Spring的AOP使用的就是设计模式里的代理模式,实现了切面编程,在调用某个方法的前后做出相应的操作,这些都可以自定义实现。


今日总访问量 加载中…
今日总访客数 加载中…
本站总访问量 加载中…
本站总访客数 加载中…
本页总阅读量 加载中…
本页总访客数 加载中…