近来比较闲,又看来下java代理的api 感觉之前对他的理解不是很深 现在又重新看了一遍 记录下自己的感受吧!
那么我们认识下 什么是代理呢? 小弟语文学的不好 ,就用如下代码来说吧!
我们模仿 登录 注册 业务案列 来讲解
/**
* 定义登录接口
**/
interface login{
boolean login(String username,String password);
boolean creadUser(String username,String password);
}
/**
* 实现登录接口
**/
class loginImpl implements login {
@Override
public boolean login(String username, String password) {
System.out.println("出来核心登录逻辑"+ "帐号是 : "+username +" 密码是: "+ password);
return true;
}
@Override
public boolean creadUser(String username, String password) {
System.out.println("我只是注册 不需要家其他业务处理" +" 注册的帐号: "+username +" 注册时的密码 : "+password);
return true;
}
}
/**
*
* 登录成功也需要添加业务逻辑
* @author jade
*
*/
class Pox extends loginImpl{
@Override
public boolean login(String username, String password) {
System.out.println("登录前业务添加逻辑 pox 1 静态代理");
boolean is= super.login(username, password);
System.out.println("登录后业务添加逻辑 pox 1 静态代理");
return is;
}
}
/** ----------------------------- 讲解代理 开始 end ***/
如上 Pox 的存在原因是因为需求的变动,又不想去改动原来的业务 所以他就出现了! Pox 就是传说中的代理
上面代理的缺点显易见 - 一个代理只能为一个接口服务 为了解决这个问题 java 就出来了动态代理
那就何为动态代理 ? 说白了就是 一个接口《java.lang.reflect.invocationHandler》 一个类《java.lang.reflect 类 Proxy》 如何不是和了解的 话几分钟看下api 好那我们把上面的静态代理修改成jdk 动态代理
class Pox2 implements InvocationHandler{
private Pox p;
Pox2(){};
Pox2(Object o){
this.p=o;
}
//
// Object getPox(Object o){
//
// this.p = o;
// //取得代理对象
// return Proxy.newProxyInstance(o.getClass().getClassLoader(),
// o.getClass().getInterfaces(), this); // 得到代理对象有很多方式 可以参阅 api 我这里写了两种一个是通过构造函数得到 一个是通过调用getPox :查了网上论坛大部分用//的是getPox
//
// }
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object r=null;
// 如下演示 业务处理
if(method.getName().equals("login")){
System.out.println("登录前业务添加逻辑 pox 2 动态代理");
r= method.invoke(p, args);
System.out.println("登录后业务添加逻辑 pox 2 动态代理");
}else{
r= method.invoke(p, args);
}
return r;
}
}
public class StadyPox {
public static void main(String[] args) {
InvocationHandler proxy2 = new Pox2(new loginImpl());
login login3=(login) Proxy.newProxyInstance(loginImpl.class.getClassLoader(),loginImpl.class.getInterfaces() , proxy2);
login3.login("c", "d");
login3.creadUser("e", "f");
</pre><pre name="code" class="java">//---------------------- 如上是通过构造函数 实现的 如下是直接通过getPox()得到
<pre name="code" class="java" style="color: rgb(146, 147, 175); font-size: 11px;">// login login2 = (login) proxy2.getPox(new loginImpl());
// login2.login("a", "b");
// <span style="font-family: Times;">login2</span><span style="font-family: Times;">.creadUser("e", "f");</span>
}}
关于动态代理的讲解就到这里了 看下
Proxy.newProxyInstance(loginImpl.class.getClassLoader(),loginImpl.class.getInterfaces() , proxy2) 你看到了什么呢? loginImpl.class.getInterfaces() ?? 这个的意思就是 他必须有实现接口 那就是jdk 动态代理 必须要有接口 才能使用
那如果在没有接口的情况下 那我们如何实现动态代理 ?? cglib 代理
cglib 代理 其原理是 继承实现类 在继承的原则下面覆盖父类方法体 也就是 final 类不能代理 因为 他不能被继承
再次模拟 登录业务 讲解 cglib
class loginImpl2 {
public boolean login(String username, String password) {
System.out.println("出来核心登录逻辑"+ "帐号是 : "+username +" 密码是: "+ password);
return true;
}
public boolean creadUser(String username, String password) {
System.out.println("我只是注册 不需要家其他业务处理" +" 注册的帐号: "+username +" 注册时的密码 : "+password);
return true;
}
}
由上面代码可以看出 , 没有实现接口 。如下写cglib 代理类 写法方式和jdk 代理类似
class cglib implements MethodInterceptor{
private Object pox;
public Object getPox(Object o) {
pox = o;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.pox.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
@Override
// 回调方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("事物开始");
proxy.invokeSuper(obj, args);
System.out.println("事物结束");
return null;
}
}
以上就是cglib动态代理 来个测试下吧!
class TestCglib {
public static void main(String[] args) {
loginImpl2 login4 = new loginImpl2();
cglib cglibProxy = new cglib();
loginImpl2 hw = (loginImpl2) cglibProxy.getInstance(login4);
System.out.println(hw.getClass().getSuperclass());
System.out.println("ssksksk " + login4.getClass().getSuperclass());
hw.login("aa", "bb");
}
}
得出的结果:
class jada.java.lang.reflect.loginImpl2
ssksksk class java.lang.Object
事物开始
出来核心登录逻辑帐号是 : aa 密码是: bb
事物结束
class jada.java.lang.reflect.loginImpl2 有此可以得出 --他说继承了 loginImpl2
开始出来个疑问 直接打印代理类
System.out.println(hw) 结果是null 并且它执行了一次 <span style="color: rgb(146, 147, 175);font-size:18px;"></span><pre name="code" class="java"> public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable
同样的方式 我打印了 jdk动态实现的
public class StadyPox {
public static void main(String[] args) {
loginImpl a = new loginImpl();
InvocationHandler proxy2 = new Pox2(a);
login login3 = (login) Proxy.newProxyInstance(
loginImpl.class.getClassLoader(),
loginImpl.class.getInterfaces(), proxy2);
System.out.println(a);
System.out.println(login3);
login3.login("c", "d");
// login login2 = (login) new Pox2().bingTage(new loginImpl());
// login2.login("a", "b");
}
}
出来的结果是:
jada.java.lang.reflect.loginImpl@2e8f4fb3
jada.java.lang.reflect.loginImpl@2e8f4fb3
登录前业务添加逻辑 pox 2 动态代理
出来核心登录逻辑帐号是 : c 密码是: d
登录后业务添加逻辑 pox 2 动态代理