简介
- 首先感谢沽泡学院 tom 老师
- 代理模式是一种结构型模式
- 代理模式就是代理对象帮被代理对象处理一些问题, 类似中介, 客户只要结果, 中介怎么搞是他的事儿, 他可能再处理过程中赚外快什么的
- 代理模式的应用: spring中的aop, 日常工作中记录日志, 统计时间,权限控制等
- 这里我们使用一个客户端代理访问google举例, 具体细节可能不合适, 意会、意会、意会...
静态代理
/**
* 一个服务器接口, 服务器有很多功能, 可以用来路由, 建站等...
*/
public interface Server {
boolean internetgoogle(Boolean ispass);
boolean internetbaidu(Boolean ispass);
}
/**
* @ClassName: HKProxyServer
* @description [静态代理类, 帮助被代理对象访问url, 静态代理类和被代理对象实现同一接口, 唯一的区别就是代理类持有被代理对象引用, ]
* 每次修改接口, 代理类和被代理类都要实现相同的方法, 静态代理, 要做的事情已经是确定的, 只是表面上换了个人去做
* @create 2018-03-31 上午7:56
**/
public class HKProxyServer implements Server{
//传入客户端信息
private Server client;
public HKProxyServer(Server client) {
this.client = client;
}
@Override
public boolean internetgoogle(Boolean ispass) {
System.out.println("香港代理: ");
return client.internetgoogle(true);
}
@Override
public boolean internetbaidu(Boolean ispass) {
System.out.println("香港代理: ");
return client.internetbaidu(true);
}
}
/**
* @ClassName: ChinaServer
* @description [描述该类的功能]
* @create 2018-03-31 上午7:45
**/
public class ChinaClient implements Server {
@Override
public boolean internetgoogle(Boolean ispass) {
if(ispass != null && ispass){
System.out.println(" 请求地址: www.google.com 通过");
return true ;
}else{
System.out.println(" 请求地址: www.google.com 拒绝");
return false;
}
}
@Override
public boolean internetbaidu(Boolean ispass) {
System.out.println(" 请求地址: www.baidu.com 通过");
return true;
}
}
public class AccessGoogle {
@Test
public void tryToAccessGoogle(){
Server chinaServer = new ChinaClient();
//访问不了google
Assert.assertFalse(chinaServer.internetgoogle(null));
//可以访问baidu
Assert.assertTrue(chinaServer.internetbaidu(null));
System.out.println("--------------------------------------------------通过代理访问--------------------------------------------------");
Server proxyServer = new HKProxyServer(chinaServer);
//可以访问google
Assert.assertTrue(proxyServer.internetgoogle(null));
//可以访问baidu
Assert.assertTrue(proxyServer.internetbaidu(null));
}
}
jdk实现动态代理
/**
* @ClassName: HKProxyServer
* @description [使用jdk动态代理实现, 不用实现与被代理类相同的接口, 接口增加方法也与我无关, 动态调用被代理类方法,
* 在调用方法前我可以输出日志, aop, 但是调用的方法的对象是传入的client对象]
* @create 2018-03-31 上午7:56
**/
public class HKProxyServer implements InvocationHandler {
//传入客户端信息
private Server client;
public HKProxyServer(Server client) {
this.client = client;
}
public Object getInstence(){
Class<?> clazz = client.getClass();
//用来生成一个新的对象(字节码重组来实现)
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
//如果直接返回传入对象就不会调用下面的invoke方法
// return client;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
args = new Object[]{true};//代理执行方法前可以搞事情
System.out.println("mylog +++++++++ 动态代理调用方法 " + method.getName());
return method.invoke(this.client, args);
}
}
/**
* @ClassName: ChinaServer
* @description [描述该类的功能]
* @create 2018-03-31 上午7:45
**/
public class ChinaClient implements Server {
@Override
public boolean internetgoogle(Boolean ispass) {
System.out.println(this);
if(ispass){
System.out.println("请求地址: www.google.com 通过");
return true ;
}else{
System.out.println("请求地址: www.google.com 拒绝");
return false;
}
}
@Override
public boolean internetbaidu(Boolean ispass) {
System.out.println(this);
System.out.println("请求地址: www.baidu.com 通过");
return true;
}
}
public class AccessGoogle {
@Test
public void tryToAccessGoogle(){
//代理对象内部使用传入de被代理对象调用方法(等价 new Object().methodxx())
Server chinaClient = new ChinaClient();
Server proxyServer = (Server)new HKProxyServer(chinaClient).getInstence();
Assert.assertTrue(proxyServer.internetgoogle(false));
Assert.assertTrue(proxyServer.internetbaidu(true));
Assert.assertFalse(chinaClient.equals(proxyServer));
}
}
cglib实现动态代理
/**
* @ClassName: HKProxyServer
* @description [使用cglib实现动态代理, 客户端都不用创建对象, 对象由框架创建载入, 体现在客户端像是用接口调用方法]
* @create 2018-03-31 上午7:56
**/
public class HKProxyServer implements MethodInterceptor {
public Object getInstence(Class<?> clazz){
Enhancer enhancer = new Enhancer();
//要把哪个设置为即将生成的新类父类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("mylog +++++++++++++++ cglib代理实现: 调用方法" + method.getName());
return methodProxy.invokeSuper(o,objects);
}
}
public class ChinaClient implements Server {
@Override
public boolean internetgoogle(Boolean ispass) {
System.out.println(this);
if(ispass){
System.out.println("请求地址: www.google.com 通过");
return true ;
}else{
System.out.println("请求地址: www.google.com 拒绝");
return false;
}
}
@Override
public boolean internetbaidu(Boolean ispass) {
System.out.println(this);
System.out.println("请求地址: www.baidu.com 通过");
return true;
}
}
public class AccessGoogle {
@Test
public void tryToAccessGoogle(){
//不需要再new对象,传入chinaclient.class即可, 然后使用接口调用方法, 内部创建了个新的子类对象来调用指定方法
Server proxyServer = (Server)new HKProxyServer().getInstence(ChinaClient.class);
Assert.assertTrue(proxyServer.internetgoogle(true));
Assert.assertTrue(proxyServer.internetbaidu(true));
}
}
三种代理方式的分析
- 静态代理: 要做的事情已经是确定的, 只是表面上换了个人去做,代理对象和被代理对象实现同样的接口,实际通过传入对象调用
- jdk动态代理: 与静态代理效果相同, 但是java通过反射实现代理类不用实现与被代理对象同样的接口, 也可以根据传入方法调用被代理对象的方法, 传入对象调用
- cglib动态代理: 只需要传入被代理对象的类名, 内部会实现创建对象到调用的过程,客户端不需要创建具体的对象, 接口调用方法
代码路径
https://github.com/offline7LY/designpattern