标签:
JDK动态代理
一个接口
package _6JDK动态代理; public interface PersonDao { public Object update(); public void delete(); public void insert(); }接口实现类
package _6JDK动态代理; public class PersonDaoImpl implements PersonDao { @Override public void delete() { // TODO Auto-generated method stub System.out.println("delete"); } @Override public void insert() { // TODO Auto-generated method stub System.out.println("insert"); } @Override public Object update() { // TODO Auto-generated method stub System.out.println("update"); return "update_success"; } }在代理中用来装配的模块
package _6JDK动态代理; public class Transaction { public void beginTransaction(){ System.out.println("开启事务"); } public void commit(){ System.out.println("结束事务"); } }在拦截器中装配模块
package _6JDK动态代理; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 拦截器 * @author Think * 1、引入目标类 * 2、引入事务 * 3、通过构造函数给目标类和事务赋值 * 4、填充invoke方法 * */ //需要实现InvocationHandler,所以才说是jdk动态代理 public class PersonInterceptor implements InvocationHandler{ private Object target;//目标类 private Transaction transsaction;//引入事务 public PersonInterceptor(Object target,Transaction transaction){ this.target = target; this.transsaction = transaction; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在这里把想要组合在一起的内容组合起来 //只需要组合这一次,以后就不用管了,不像静态代理,每次都要重新写 //感觉静态代码更像是装饰设计模式 // TODO Auto-generated method stub this.transsaction.beginTransaction(); //返回的是调用的方法的返回值 Object message = method.invoke(this.target, args);//调用目标类的方法 this.transsaction.commit(); return message; } }开始使用代理
package _6JDK动态代理; import java.lang.reflect.Proxy; public class test { public static void main(String[] args) { // TODO Auto-generated method stub Object target = new PersonDaoImpl(); Transaction transaction = new Transaction(); PersonInterceptor interceptor = new PersonInterceptor(target, transaction); /** * 1、目标类的类加载器 * 2、目标类实现的所有的接口 * 3、拦截器 */ PersonDao persondao = (PersonDao) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); System.out.println(persondao.update()); } }
JDK的动态代理必须具备四个条件:
目标接口
目标类
拦截器
代理类
总结:
1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有。
2、生成的代理类的所有的方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体。
3、利用JDKProxy方式必须有接口的存在。
4、invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型。
JDK动态代理优化,类似于struts2的拦截器模式。
拦截器接口,用来装配的
package _7JDK动态代理优化; public interface Interceptor { public void interceptor(); }接口实现,全部是拦截器角色,用来装配的
package _7JDK动态代理优化; public class Logger implements Interceptor{ @Override public void interceptor() { // TODO Auto-generated method stub System.out.println("logging"); } }
package _7JDK动态代理优化; public class Privilege implements Interceptor{ @Override public void interceptor() { // TODO Auto-generated method stub System.out.println("privilege"); } }
package _7JDK动态代理优化; public class Security implements Interceptor{ @Override public void interceptor() { // TODO Auto-generated method stub System.out.println("security"); } }
目标类接口,也就是被代理的类
package _7JDK动态代理优化; public interface SalaryManager { public void showSalary(); }
目标类接口的实现
package _7JDK??????????; public class SalaryManagerImpl implements SalaryManager { public void showSalary() { System.out.println("查看工资"); } }目标类和装配模板装配在一起,模板有多个,类似于struts2的拦截器模式
package _7JDK??????????; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; public class SalaryInterceptor implements InvocationHandler{ private Object target; //把所有切面都放在集合里面 这样????改变的也是结合,下面的invoke的切面整合不用因为增加一个??修改 private List<Interceptor> interceptors; public SalaryInterceptor(Object target,List<Interceptor> interceptors){ this.target = target; this.interceptors = interceptors; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { for(Interceptor interceptor:interceptors){ interceptor.interceptor(); } method.invoke(this.target, args); return null; } }代理测试类:多个拦截器放在集合里面
package _7JDK动态代理优化; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; import org.junit.Test; public class SalaryTest { @Test public void test(){ Object target = new SalaryManagerImpl(); Logger logger = new Logger(); Security security = new Security(); Privilege privilege = new Privilege(); List<Interceptor> interceptors = new ArrayList<Interceptor>(); interceptors.add(logger); interceptors.add(security); interceptors.add(privilege); SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors); SalaryManager salaryManager = (SalaryManager)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); salaryManager.showSalary(); } }
cglib产生的代理类是目标类的子类,其他和jdk动态代理一样
1、 CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
2、 用CGlib生成代理类是目标类的子类。
3、 用CGlib生成 代理类不需要接口
4、 用CGLib生成的代理类重写了父类的各个方法。
5、 拦截器中的intercept方法内容正好就是代理类中的方法体
拦截器接口
package _8cglib动态代理; public interface Interceptor { public void interceptor(); }实现类
package _8cglib动态代理; public class Logger implements Interceptor{ @Override public void interceptor() { // TODO Auto-generated method stub System.out.println("logging"); } }
package _8cglib动态代理; public class Privilege implements Interceptor{ @Override public void interceptor() { // TODO Auto-generated method stub System.out.println("privilege"); } }
package _8cglib动态代理; public class Security implements Interceptor{ @Override public void interceptor() { // TODO Auto-generated method stub System.out.println("security"); } }目标类,和jdk的区别就是这里只有具体类,没有对应的接口
package _8cglib动态代理; public class SalaryManagerImpl { public void showSalary() { System.out.println("工资"); } }装配类,装配方式和jdk动态代理有点区别
package _8cglib???????; import java.lang.reflect.Method; import java.util.List; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class SalaryInterceptor implements MethodInterceptor{ private Object target; private List<Interceptor> interceptors; public SalaryInterceptor(Object target,List<Interceptor> interceptors){ this.target = target; this.interceptors = interceptors; } //固定写法 public Object createProxy(){ Enhancer enhancer = new Enhancer(); enhancer.setCallback(this); enhancer.setSuperclass(this.target.getClass()); return enhancer.create(); } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { // TODO Auto-generated method stub for(Interceptor interceptor:interceptors){ interceptor.interceptor(); } arg1.invoke(this.target, arg2); return null; } }代理测试类
package _8cglib动态代理; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; import org.junit.Test; public class SalaryTest { @Test public void test(){ Object target = new SalaryManagerImpl(); Logger logger = new Logger(); Security security = new Security(); Privilege privilege = new Privilege(); List<Interceptor> interceptors = new ArrayList<Interceptor>(); interceptors.add(logger); interceptors.add(security); interceptors.add(privilege); SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors); SalaryManagerImpl proxy = (SalaryManagerImpl)interceptor.createProxy(); proxy.showSalary(); } }
spring有两种代理方式:
1. 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
2. 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
总结:不管采用JDK动态代理生成代理类还是采用CGLIB生成动态代理类。目标类中的所有方法都被拦截下来。而在哪个方法里做比如权限的判断、安全性的检查等一系列工做必须在拦截器中作相应的判断。但是这样的编程形式给程序的编写带来了一定的麻烦。
1、 在拦截器中控制哪些方法将被做权限判断、安全性检查等是一件比较困难的事情。
A. 采取这样的配置目标类只能是一个,所以如果用这种方法做权限控制,得写很多代理,这样给代码的书写造成了困难。
B. 每一个类中的每一个方法如果都有不同的权限(实际的系统往往都是这样的),在拦截器中的判断代码书写会很困难。
2、 这样的代码也会导致硬编码,也就是说我们必须在拦截器中写一些权限判断等事情,会导致拦截器中代码量的增大,造成维护的麻烦。
标签:
原文地址:http://my.oschina.net/u/2356176/blog/469093