代理模式

一、什么是代理
代理对象代替被代理对象干活


二、代理作用
对被代理对象方法的增强


三、代理的种类:静态代理、动态代理
3.1、静态代理
3.1.1、定义抽象行为的类[抽象类、接口]
3.1.2、定义具体类实现抽象行为
3.1.3、定义代理类实现和具体类相同接口
3.1.4、代理类中必须持有实现类对应的引用
3.1.5、缺点:只能代理一类对象
3.2、动态代理
3.2.1、动态代理2种:JDK动态代理、cglib代理
3.2.2、JDK动态代理:为实现接口的类动态创建代理类(即:帮你生成代理对象, 只能代理实现接口的类),然后调用回调方法。

 

四、代码演示

4.1静态代理

package com.statics.proxy;

/**
 * 接口
 */
public interface IFunction {
    public String getBtnName();
    void click();
}


package com.statics.proxy;

/**
 * 实体对象:按钮
 */
public class Button implements IFunction {

    private String btnName;

    public String getBtnName(){
        return btnName;
    }

    public Button(String btnName){
        this.btnName = btnName;
    }

    @Override
    public void click() {
        System.out.println(this.btnName+"按钮被点击了");
    }
}


package com.statics.proxy;

/**
 * 负责鉴权的代理类。即:在调用按钮前,检查是否有权限
 */
public class ButtonProxy implements IFunction {

    //持有被代理对象的引用
    private IFunction function;

    //定义角色名称
    private String roleName;

    public ButtonProxy(IFunction function,String roleName){
         this.function = function;
         this.roleName = roleName;
    }

    @Override
    public String getBtnName() {
        return null;
    }

    @Override
    public void click() {
        if("admin".equals(roleName)){
            System.out.println("权限校验合法");
            function.click();
        }else{
            System.out.println("没有权限点击"+function.getBtnName());
        }

    }
}


package com.statics.proxy;

/**
 * 静态代理测试类
 */
public class TestStaticsProxy {

    public static void main(String[] args) {
        //创建提交按钮
        IFunction target = new Button("提交按钮");
        //没有代理之前的调用
        target.click();
        System.out.println("====================");
        //创建代理对象
        IFunction proxy = new ButtonProxy(target,"admin");
        //IFunction proxy = new ButtonProxy(target,"guest");
        //代理后点击调用方法
        proxy.click();
    }
}

4.2、动态代理

4.2.1、JDK动态代理:创建代理对象,然后代理对象调用回调函数,最后完成代理对被代理对象增强

package com.dynamic.proxy;

public interface IFunction {
    void click();
    void dbClick();
    String getName();
}


package com.dynamic.proxy;

public class Window implements IFunction {

    private String name;

    public Window(String name){
        this.name = name;
    }

    @Override
    public void click() {
        System.out.println(this.name+"被单击了");
    }

    @Override
    public void dbClick() {
        System.out.println(this.name+"被双击了");
    }

    @Override
    public String getName() {
        return name;
    }
    
}

package com.dynamic.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK动态代理:只能代理实现接口的类
* 如果要加注解,需要在接口上面加注解,不在实现类上加。否则Method.isAnnotationPresent(Xxx.class)找不到 */ public class ObjectProxy { //持有目标代理类对象 private Object target; public ObjectProxy(){ } public ObjectProxy(Object target){ this.target = target; } /** * 定义生成目标对象代理对象的方法 * 生成代理对象 * Proxy.newProxyInstance第三个参数是回调,代理对象执行 */ public Object createProxy(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new Handle()); } /*** * 回调处理的内部类 */ private class Handle implements InvocationHandler{ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { validateLogin(); validateRole(); Object obj = method.invoke(target,args); requestData(); responseData(); return obj; } } private void validateLogin(){ System.out.println("验证登录,验证成功"); } private void validateRole(){ System.out.println("验证角色,验证成功"); } private void requestData(){ System.out.println("请求服务器端数据"); } private void responseData(){ System.out.println("返回服务器端数据"); } } package com.dynamic.proxy; public class TestDynamicProxy { public static void main(String[] args) { //创建目标代理对象 IFunction target = new Window("模态窗口"); target.click(); target.dbClick(); System.out.println("===================="); //创建一个代理对象 ObjectProxy op = new ObjectProxy(target); IFunction proxy = (IFunction) op.createProxy(); proxy.click(); System.out.println("===================="); proxy.dbClick(); } }

 

5、cglib代理

JDK代理要求被代理的类必须实现接口,有很强的局限性。而CGLIB动态代理则没有此类强制性要求。简单的说,CGLIB会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。在CGLIB底层,其实是借助了ASM这个非常强大的Java字节码生成框架。
package com.cglib.proxy;

/**
 * 被代理类
 */
public class Button {

    public void click() {
        System.out.println("按钮被点击了");
    }

}


package com.cglib.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * MethodInterceptor拦截
 */
public class ButtonMethodInterceptor implements MethodInterceptor {

    /**
     *
     * @param o              被代理对象
     * @param method        代理增加方法
     * @param objects       代理方法参数
     * @param methodProxy  代理方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before:权限检查");
        Object object = methodProxy.invokeSuper(o,objects);
        System.out.println("after:权限检查通过");
        return object;
    }

}


package com.cglib.proxy;

import org.springframework.cglib.proxy.Enhancer;

/**
 * Cglib动态代理创建
 */
public class ButtonProxy {

    public Object createCglibProxy(){
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(Button.class);
        enhancer.setCallback(new ButtonMethodInterceptor());
        Button proxy = (Button)enhancer.create();
        return proxy;
    }

    public static void main(String[] args) {
        Button buttonProxy = (Button)new ButtonProxy().createCglibProxy();
        buttonProxy.click();
    }
}

 

posted @ 2018-01-17 23:11  N神3  阅读(141)  评论(0编辑  收藏  举报