动态代理: 相对于静态代理(字节码一上来就创建好,并完成加载)相比,具有字节码随用随创建,随用随加载的特点。主要作用是在不修改源码的基础上对方法进行增强。
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();
}