代理模式
代理模式是设计模式中非常重要的一种类型,代理模式从类型上来说,可以分为静态代理和动态代理两种类型。
静态代理
1.定义一个共用的接口
public interface UserService {
void query();
}
2.目标类实现上述接口
public class UserServiceImpl implements UserService {
public void query() {
System.out.println("查询用户信息");
}
}
3.代理类实现代码增强
public class Proxy implements UserService{
private UserService userService ;
public Proxy(UserService userService ){
this.userService = userService ;
}
public void query() {
System.out.println("开始查询");
userService.query();
System.out.println("结束查询");
}
}
4.通过调用代理类实现方法功能强化
缺点:
编译器就确定好代码,不能处理未知类型的数据啊,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。因此,动态代理将静态代理在编译器的代码增强延缓到运行期实现。
动态代理
(1)Proxy 类提供了用于创建动态代理类和实例对象的方法,它是所创建的动态代理类的父类。
(2)InvocationHandler 接口是代理处理程序类的实现接口,每一个被生成的代理类实例都可以提供一个相关的代理处理程序类,代理类实例的方法被调用时会回调invoke()方法。
1.定义共用接口
public interface Cacu {
int plus(int a,int b);
int multiply(int a,int b);
}
2.目标类实现该接口
public class CacuImp implements Cacu {
@Override
public int plus(int a, int b) {
return a+b;
}
@Override
public int multiply(int a, int b) {
return a*b;
}
}
3.创建动态代理类
public class ProxyTest {
private static Object getProxy(final Object target) throws Exception{
Class proxyClazz = Proxy.getProxyClass(target.getClass().getClassLoader(),target.getClass().getInterfaces());
Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
/**
* @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.
* 在代理实例上的方法调用中传递的参数
*/
Object proxy = constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "方法开始执行...");
Object result = method.invoke(target,args);
System.out.println(method.getName() + "方法执行结束...");
return result;
}
});
return proxy;
}
//精简版
private static Object getProxy2(Object target) throws Exception {
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "方法开始执行...");
Object result = method.invoke(target,args);
System.out.println(method.getName() + "方法执行结束...");
return result;
}
});
return proxy;
}
//测试
public static void main(String[] args) throws Exception {
Cacu target = new CacuImp();
Cacu proxy = (Cacu) getProxy(target);
proxy.plus(1,1); //代理对象每次调用方法都会执行invoke里的方法
proxy.multiply(2,2);
}
}
类加载器:
1:JDK内部需要通过类加载作为缓存的key
2:需要类加载器生成class
动态代理局限:
JDK动态代理只能代理接口。因为生成的代理类已经继承了Proxy类,Java是单继承的,所以没法再继承另外一个类了。