实现java代理一般分为静态代理和动态代理(jdk代理和cglib代理)
代理模式
简单的说就是对原有的业务进行代理,外界通过代理访问真实对象,代理类似现在的中介机构,房产中介就是一个代理,代理房东,租户只要找到代理而无须关心房东是谁,代理能在房东的基础上增强房东的行为。
代理模式代码
JAVA静态代理
业务接口
package com.rrg.proxy.jdk.staticProxy; /** * * @author abc * */ public interface Count { /** * 查询余额 */ public void queryMoney(); /** * 转账 */ public void transferMoney(); }
业务实现类
package com.rrg.proxy.jdk.staticProxy; public class CountImpl implements Count { public void queryMoney() { System.out.println("queryMoney()"); } public void transferMoney() { System.out.println("transferMoney()"); } }
代理
package com.rrg.proxy.jdk.staticProxy; /** * java静态代理 * @author abc * */ public class JDKStaticProxy implements Count { private CountImpl countImpl; public JDKStaticProxy(CountImpl countImpl) { this.countImpl = countImpl; } public void queryMoney() { System.out.println("===开始查询==="); countImpl.queryMoney(); System.out.println("===查询结束==="); } public void transferMoney() { System.out.println("===开始转账==="); countImpl.transferMoney(); System.out.println("===转账成功==="); } }
测试
/** * jdk静态代理 */ @Test public void test1(){ CountImpl impl = new CountImpl(); JDKStaticProxy proxy = new JDKStaticProxy(impl); proxy.queryMoney(); System.out.println(); proxy.transferMoney(); }
JAVA动态代理
模拟业务方法接口UserService.java
package com.rrg.proxy.jdk.dynamic;
/**
* 创建业务接口
* @author abc
*
*/
public interface UserService {
/**
* 新增人员
*/
public void add();
}
业务方法实现UserServiceImpl.java
package com.rrg.proxy.jdk.dynamic;
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("add()");
}
}
代理类,负责处理代理
package com.rrg.proxy.jdk.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKDynamicHandler implements InvocationHandler { private UserService userService; public JDKDynamicHandler(UserService userService) { super(); this.userService = userService; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("===添加人员处理==="); Object result = method.invoke(userService, args); System.out.println("===添加人员完毕==="); return result; } public Object getProxy() { //通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用 //创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类 return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), this.userService.getClass().getInterfaces(), this); } }
测试
/** * jdk动态代理 */ @Test public void test2() { UserService userService = new UserServiceImpl(); JDKDynamicHandler handler = new JDKDynamicHandler(userService); UserService proxy = (UserService) handler.getProxy(); proxy.add(); }
CGLIB动态代理
不需要接口直接代理实现类
业务实现类
package com.rrg.proxy.cglib; public class BookFacadeImpl { /** * 添加图书 */ public void addBook() { System.out.println("addBook()"); } }
代理
package com.rrg.proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class BookFacadeCglib implements MethodInterceptor { private BookFacadeImpl bookService; public Object getInstance(BookFacadeImpl bookService) { Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类 enhancer.setSuperclass(this.bookService.getClass()); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类) //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦 enhancer.setCallback(this); // 创建动态代理类对象并返回 return enhancer.create(); } //回调方法 public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("===准备添加图书==="); methodProxy.invokeSuper(object, args); System.out.println("===完成添加图书==="); return null; } }
测试
/** * cglib动态代理 */ @Test public void test3() { BookFacadeImpl bookService = new BookFacadeImpl(); BookFacadeCglib cglib = new BookFacadeCglib(); BookFacadeImpl bookCglib = (BookFacadeImpl) cglib.getInstance(bookService); bookCglib.addBook(); }
总结
(1)静态代理是在编译时创建一个业务代理类,通过代理访问同名方法,实现对原方法的包装(代理类继承业务类)
(2)JDK动态代理通过接口的方法名,在动态的代理类调用同名业务方法,实现对原方法的包装(实现InvocationHandler)
(3)CGLIB动态代理通过继承业务类,创建出一个增强的业务类(实现MethodInterceptor)
代理是一个AOP思想的体现,切面编程对业务方法的前后进行增强
在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理