Java代理技术

来源:互联网 发布:春运迁徙大数据图 编辑:程序博客网 时间:2024/05/22 12:37
1 Java静态代理
代理模式的作用是:为其他对象提供一种代理以控制对目标对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式一般涉及到的角色有:
Ø抽象角色:声明真实对象和代理对象的共同接口;
Ø真实角色(目标对象):代理角色所代表的真实对象,是我们最终要引用的对象。
Ø代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

抽象角色UserManager.java
public interface UserManager {public void save(String name,String pwd);public void update(String name,String pwd,String repwd);public void delete(int id);public String select(int id);}

真实角色:UserManagerImpl.java
public class UserManagerImpl implements UserManager{public void save(String name, String pwd) {System.out.println("UserManagerImpl ------save()");}public void update(String name, String pwd, String repwd) {System.out.println("UserManagerImpl ------save()");}public void delete(int id) {System.out.println("UserManagerImpl ------save()");}public String select(int id) {return "UserManagerImpl select";}}


代理角色: UserManagerSPorxy.java
public class UserManagerSPorxy implements UserManager {UserManager userManager;public UserManagerSPorxy(UserManager userManager){this.userManager = userManager;}public void save(String name, String pwd){log();userManager.save(name, pwd);}public void update(String name, String pwd, String repwd){log();userManager.update(name, pwd, repwd);}public void delete(int id) {log();userManager.delete(id);}public String select(int id) {log();return userManager.select(id);}public void log(){System.out.println("-------write log into logfile............");}}

测试程序TestStaticPorxy.java
public class TestStaticPorxy {public static void main(String[] args) {UserManager userManager = new UserManagerSPorxy(new UserManagerImpl());userManager.delete(3);userManager.save("aa", "bb");}}

结果:

优点:不需要修改目标对象就实现了功能的增加。
缺点:
Ø真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。如果事先并不知道真实角色则无法使用。
Ø一个真实角色必须对应一个 代理角色,如果大量使用会导致类的急剧膨胀;
如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决


2、Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类: 2 Java动态代理

1)、Interface InvocationHandler:该接口中仅定义了一个方法
public object invoke(Object obj,Method method, Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method被代理的方法,args为该方法的参数数组。 这个抽象方法在代理类中动态实现。

2)、Proxy:该类即为动态代理类,作用类似于上例中的UserManagerSPorxy,其中主要包含以下内容

protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例。

参数说明: 
ClassLoader loader:类加载器 
Class<?>[] interfaces:得到全部的接口 
InvocationHandler h:得到InvocationHandler接口的子类实例 

Ps:类加载器 
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类; 
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 


动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性

因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。


动态代理示例: 

package net.battier.dao;public interface BookFacade {public void addBook();}

package net.battier.dao.impl;import net.battier.dao.BookFacade;public class BookFacadeImpl implements BookFacade {@Overridepublic void addBook() {System.out.println("增加图书方法。。。");}}BookFacadeProxy.javapackage net.battier.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * JDK动态代理代理类 *  * @author student *  */public class BookFacadeProxy implements InvocationHandler {private Object target;/** * 绑定委托对象并返回一个代理类 * @param target * @return */public Object bind(Object target) {this.target = target;//取得代理对象return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)}@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;}}


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修饰的类进行代理。 
示例 

package net.battier.dao;public interface BookFacade {public void addBook();}

package net.battier.dao.impl;/** * 这个是没有实现接口的实现类 *  * @author student *  */public class BookFacadeImpl1 {public void addBook() {System.out.println("增加图书的普通方法...");}}

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;/** * 使用cglib动态代理 *  * @author student *  */public class BookFacadeCglib implements MethodInterceptor {private Object target;/** * 创建代理对象 *  * @param target * @return */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;}}

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();}}




动态代理步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理
4.通过代理调用方法

静态代理类是确实存在的 动态代理是运行期动态生成的






原创粉丝点击