動態代理: 相對於靜態代理(字節碼一上來就創建好,並完成加載)相比,具有字節碼隨用隨創建,隨用隨加載的特點。主要作用是在不修改源碼的基礎上對方法進行增強。
1. 基於接口的動態代理
涉及的類 | 提供者 | 要求 | 方法 |
---|---|---|---|
Proxy | JDK官方 | 被代理類最少實現一個接口,如果沒有則不能使用 | newProxyInstance |
public static Object newProxyInstance(ClassLoader loader,
Class<?>[ ] interfaces,
InvocationHandler h)
Parameters:
loader - the class loader to define the proxy class
interfaces - the list of interfaces for the proxy class to implement
h - the invocation handler to dispatch method invocations to
Returns:
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
ClassLoader loader: 類加載器
它是用於加載代理對象的字節碼文件的。和被代理對象使用相同的類加載器。固定寫法。
Class<?>[] interfaces: 字節碼數組
它是用於讓代理對象和被代理對象實現相同的方法。固定寫法。
InvocationHandler h: 用於提供增強的代碼
它是讓我們寫如何代理。我們一般都是寫一個該接口的實現類,通常情況下都是匿名內部類,但不是必須的。此接口的實現類都是誰用誰寫。
使用示例:
public interface UserService {
Float sell(Float money);
}
public class UserServiceImpl implements UserService {
public Float sell(Float money) {
return money;
}
public void show() {
System.out.println("實現類特有方法");
}
}
public static void main(String[] args) {
//匿名內部類訪問外部變量時,該成員必須爲final
final UserServiceImpl userService = new UserServiceImpl();
//只能強轉爲接口類型而不能是實現類類型
UserService proxyBasedOnInterface = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),
new InvocationHandler() {
/**
*作用:代理對象執行被代理對象的 任何接口方法 都會經過該方法
* @param proxy 代理對象的引用
* @param method 執行的方法
* @param args 方法的參數
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("sell".equals(method.getName())) {
//方法的內部邏輯的增強
System.out.println("方法內部邏輯增強");
//方法參數的增強
Float money = (Float) args[0] * 2;
//方法返回值的增強
Float returnValue = (Float)method.invoke(userService, money) + 100f;
return returnValue;
}
return null;
}
});
proxyBasedOnInterface.sell(1024f);
}
2. 基於子類的動態代理
涉及的類 | 提供者 | 要求 | 方法 |
---|---|---|---|
Enhancer | 第三方cglib庫 | 被代理類不能是最終類 | create |
public static Object create(Class type,Callback callback)
Helper method to create an intercepted object. For finer control over the generated instance, use a new instance of Enhancer instead of this static method.
Parameters:
type - class to extend or interface to implement
callback - the callback to use for all methods
Class type: 字節碼對象
它是用於指定被代理對象的字節碼。
Callback callback: 用於提供增強的代碼
它是讓我們寫如何代理。我們一般都是寫一個該接口的實現類,通常情況下都是匿名內部類,但不是必須的。此接口的實現類都是誰用誰寫。我們一般寫的都是該接口的子接口的實現類,MethodInterceptor
使用示例: 需要導入cglib庫
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
public static void main(String[] args) {
//匿名內部類訪問外部變量時,該成員必須爲final
final UserServiceImpl userService = new UserServiceImpl();
//可以強轉爲接口類型或者實現類類型,因此可以調用實現類特有方法
UserServiceImpl proxyBasedOnSubclass = (UserServiceImpl)Enhancer.create(
userService.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 {
if ("sell".equals(method.getName())) {
//方法的內部邏輯的增強
System.out.println("方法內部邏輯增強");
//方法參數的增強
Float money = (Float) args[0] * 2;
//方法返回值的增強
Float returnValue = (Float)method.invoke(userService, money) + 20f;
return returnValue;
}
System.out.println("調用了此方法");
return null;
}
});
proxyBasedOnSubclass.sell(300f);
proxyBasedOnSubclass.show();
}