JAVA的动态代理
代理模式
代理模式是经常使用的java设计模式,他的特征是代理类与委托类有一样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及过后处理消息等。代理类与委托类之间一般会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象自己并不真正实现服务,而是经过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的建立时期,代理类能够分为两种。
静态代理:由程序员建立或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态建立而成。 java
首先看一下静态代理:
一、Count.java 程序员
- package net.battier.dao;
-
-
-
-
-
-
-
- public interface Count {
-
- public void queryCount();
-
-
- public void updateCount();
-
- }
二、CountImpl.java 编程
- package net.battier.dao.impl;
-
- import net.battier.dao.Count;
-
-
-
-
-
-
-
- public class CountImpl implements Count {
-
- @Override
- public void queryCount() {
- System.out.println("查看帐户方法...");
-
- }
-
- @Override
- public void updateCount() {
- System.out.println("修改帐户方法...");
-
- }
-
- }
-
- 、CountProxy.java
- package net.battier.dao.impl;
-
- import net.battier.dao.Count;
-
-
-
-
-
-
-
- public class CountProxy implements Count {
- private CountImpl countImpl;
-
-
-
-
-
-
- public CountProxy(CountImpl countImpl) {
- this.countImpl = countImpl;
- }
-
- @Override
- public void queryCount() {
- System.out.println("事务处理以前");
-
- countImpl.queryCount();
- System.out.println("事务处理以后");
- }
-
- @Override
- public void updateCount() {
- System.out.println("事务处理以前");
-
- countImpl.updateCount();
- System.out.println("事务处理以后");
-
- }
-
- }
三、TestCount.java 设计模式
- package net.battier.test;
-
- import net.battier.dao.impl.CountImpl;
- import net.battier.dao.impl.CountProxy;
-
-
-
-
-
-
-
- public class TestCount {
- public static void main(String[] args) {
- CountImpl countImpl = new CountImpl();
- CountProxy countProxy = new CountProxy(countImpl);
- countProxy.updateCount();
- countProxy.queryCount();
-
- }
- }
观察代码能够发现每个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,并且,全部的代理操做除了调用的方法不同以外,其余的操做都同样,则此时确定是重复代码。解决这一问题最好的作法是能够经过一个代理类完成所有的代理功能,那么此时就必须使用动态代理完成。
再来看一下动态代理:
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所须要的参数 ide
能够将InvocationHandler接口的子类想象成一个代理的最终操做类,替换掉ProxySubject。 工具
Proxy类:
Proxy类是专门完成代理的操做类,能够经过此类为一个或多个接口动态地生成实现类,此类提供了以下的操做方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:获得所有的接口
InvocationHandler h:获得InvocationHandler接口的子类实例 测试
Ps:类加载器
在Proxy类中的newProxyInstance()方法中须要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,通常开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,通常对应的是jre\lib\ext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 this
动态代理
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不只简化了编程工做,并且提升了软件系统的可扩展性,由于Java 反射机制能够生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 spa
动态代理示例:
一、BookFacade.java 设计
- package net.battier.dao;
-
- public interface BookFacade {
- public void addBook();
- }
二、BookFacadeImpl.java
- package net.battier.dao.impl;
-
- import net.battier.dao.BookFacade;
-
- public class BookFacadeImpl implements BookFacade {
-
- @Override
- public void addBook() {
- System.out.println("增长图书方法。。。");
- }
-
- }
-
- 、BookFacadeProxy.java
-
- package net.battier.proxy;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
-
-
-
-
-
-
-
- public class BookFacadeProxy implements InvocationHandler {
- private Object target;
-
-
-
-
-
- public Object bind(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 result=null;
- System.out.println("事物开始");
-
- result=method.invoke(target, args);
- System.out.println("事物结束");
- return result;
- }
-
- }
三、TestProxy.java
- package net.battier.test;
-
- import net.battier.dao.BookFacade;
- import net.battier.dao.impl.BookFacadeImpl;
- import net.battier.proxy.BookFacadeProxy;
-
- public class TestProxy {
-
- public static void main(String[] args) {
- BookFacadeProxy proxy = new BookFacadeProxy();
- BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
- bookProxy.addBook();
- }
-
- }
可是,JDK的动态代理依靠接口实现,若是有些类并无实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现加强,但由于采用的是继承,因此不能对final修饰的类进行代理。
示例
一、BookFacadeCglib.java
- package net.battier.dao;
-
- public interface BookFacade {
- public void addBook();
- }
二、BookCadeImpl1.java
- package net.battier.dao.impl;
-
-
-
-
-
-
-
- public class BookFacadeImpl1 {
- public void addBook() {
- System.out.println("增长图书的普通方法...");
- }
- }
三、BookFacadeProxy.java
- package net.battier.proxy;
-
- 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 Object target;
-
-
-
-
-
-
-
- public Object getInstance(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("事物开始");
- proxy.invokeSuper(obj, args);
- System.out.println("事物结束");
- return null;
-
-
- }
-
- }
四、TestCglib.java
- package net.battier.test;
-
- import net.battier.dao.impl.BookFacadeImpl1;
- import net.battier.proxy.BookFacadeCglib;
-
- public class TestCglib {
-
- public static void main(String[] args) {
- BookFacadeCglib cglib=new BookFacadeCglib();
- BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
- bookCglib.addBook();
- }
- }