java中的代理作用:降低代码的冗余
分类:
1.静态代理
2.jdk动态代理
3.cglib动态代理
首先放上基础代码:
package com.esx.bean;/** * 性别 * @author 二师兄 * */public enum Agen { WOMAN,MAN
}
package com.esx.bean;public class User { private String username; private String userpassword; private Agen gender; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUserpassword() { return userpassword; } public void setUserpassword(String userpassword) { this.userpassword = userpassword; } public Agen getGender() { return gender; } public void setGender(Agen gender) { this.gender = gender; } public User(String username, String userpassword, Agen gender) { this.username = username; this.userpassword = userpassword; this.gender = gender; } @Override public String toString() { return "User [username=" + username + ", userpassword=" + userpassword + ", gender=" + gender + "]"; }
}
package com.esx.dao.impl;/** * 无实现类的 * @author 二师兄 * */public class NoImplUserDao { public void add() { System.out.println("无实现类的userdao执行数据库Add方法......."); }
}
package com.esx.dao.impl;import com.esx.bean.Agen;import com.esx.bean.User;import com.esx.dao.IUserdao;public class UserDao implements IUserdao{ User user=new User("张三", "123456", Agen.MAN); @Override public void save() { System.out.println(user.toString()); } @Override public void get() { System.out.println(user.getUsername()); }
}
package com.esx.dao;public interface IUserdao { public void save(); public void get();
}
package com.esx.test;
import com.esx.dao.IUserdao;/** * 静态代理 * @author 二师兄 * */public class StaticProxy implements IUserdao{ private IUserdao target; public StaticProxy(IUserdao target) { this.target=target; } @Override public void save() { long stime=System.currentTimeMillis(); target.save(); long etime=System.currentTimeMillis(); System.out.println("这个程序共执行了"+(etime-stime)+"毫秒"); } @Override public void get() { System.out.println("静态代理类执行"); target.get(); }
}
package com.esx.test;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * jdk 动态代理 * @author 二师兄 * */public class DynamicProxy implements InvocationHandler { private Object target; /*public DynamicProxy(Object target) { this.target=target; }*/ public Object getDynamicProxyTargetInstance(Object target) { this.target=target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnValue=null;
System.out.println("jdk动态代理==================================");
System.out.println("before calling :"+method); if("save".equals(method.getName())) { method.invoke(target, args); } System.out.println("after calling :"+method); return returnValue; }}
jdk动态代理是通过实现java中的InvocationHandler 通过反射的方式来进行方法的调用
通过类的加载器将实际代理类和抽象代理类加载,再通过InvocationHandler 监听类中的方法调用,这时我们可以通过方法的名字进行过滤一般的只代理特定的方法
jdk动态代理有一个弊端:就是实际代理的类必须实现一个接口;因此cglib就完美的解决了这个弊端
package com.esx.test;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;/** * * @author 二师兄 * cglib动态代理 */public class CglibProxy implements MethodInterceptor { private Object target; public Object getCglibTargetProxyInstance(Object target) { this.target=target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("cglib动态代理===============================");
System.out.println("method run before。。。。。"); Object returnValue = proxy.invokeSuper(obj, args); System.out.println("method run after..........."); return returnValue; }}
//cglib代理并不是java自身的,因此需要导入其他cglib的jar包,但是这里还是需要导入另一个asm的jar包,如果没有这个包就会报这样的错误。
因为cglib的底层使用到了asm来获取实例对象。cglib是通过实现一个拦截器来实现代理 MethodInterceptor将嗦需要代理的类进行拦截,然后创造出其代理类的子对象,然后对这个生成的代理类进行方法拦截,判断是否有这个方法的名字【还是使用method.getname()来获取方法的名字】,有就执行。cglib进行代理的时候不要求类必须实现接口, 这里虽然看起来和jdk不一样,但是楼主认为还是一样的,jdk动态代理是具有现有的接口和实现类,而cglib是通过将代理的类创造出一个实现它的子类来实现代理。但是这样使得cglib使用范围更为宽泛 比如spring中的AOP编程,但是cglib有个限制,不能代理呗final修饰的类,为什么呢?final类是最终的类,不能被实现或者继承,因此cglib是无法为其造出子类。
package com.esx.test;import org.junit.Test;import com.esx.dao.IUserdao;import com.esx.dao.impl.NoImplUserDao;import com.esx.dao.impl.UserDao;public class TestProxy { /** * 测试cglib代理 * @throws Exception */ @Test public void testCglibProxy() throws Exception { CglibProxy proxy = new CglibProxy();// 有实现类的 IUserdao userdao = (IUserdao) proxy.getCglibTargetProxyInstance(new UserDao()); userdao.save(); userdao.get();// 无实现类的 NoImplUserDao userdao1=(NoImplUserDao) proxy.getCglibTargetProxyInstance(new NoImplUserDao()); userdao1.add(); } /** * 测试jdk动态代理 * @throws Exception */ @Test public void testDynamicProxy() throws Exception { IUserdao userdao = (IUserdao) new DynamicProxy().getDynamicProxyTargetInstance(new UserDao()); userdao.save(); userdao.get(); } /** * 测试静态代理 * @throws Exception */ @Test public void testStaticProxy() throws Exception { IUserdao proxy = new StaticProxy(new UserDao()); proxy.save(); proxy.get(); }
}
以上的执行结果
asm-all-3.3.1.jar:https://mvnrepository.com/artifact/asm/asm-all/3.3.1 cglib-2.2.2.jar:https://mvnrepository.com/artifact/cglib/cglib/2.2.2
