代理

代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。

1.静态代理

2.动态代理

3.cglib代理:如果目标对象没有实现接口,用Cglib代理

静态代理总结:

1.可以做到在不修改目标对象的功能前提下,对目标功能扩展.

2.缺点:

因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护。

如何解决静态代理中的缺点呢?

答案是可以使用动态代理方式

spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。


浅谈几种设计模式--代理模式_动态代理


静态代理


/**	
 * 创建Person接口	
 */	
public interface Person {	
        void giveMoney();//上交班费	
}	
/**	
 * Student类实现Person接口。Student可以具体实施上交班费的动作	
 */	
public class Student implements Person {	
    private String name;	
    public Student(String name) {	
         = name;	
    }	
    @Override	
    public void giveMoney() {	
       System.out.println(name + "上交班费50元");	
    }	
}


/**	
 * 学生代理类,也实现了Person接口,保存一个学生实体,这样既可以代理学生产生行为	
 */	
public class StudentsProxy implements Person{	
    //被代理的学生	
    Student stu;	
    public StudentsProxy(Person stu) {	
        // 只代理学生对象	
        if(stu.getClass() == Student.class) {	
            this.stu = (Student)stu;	
        }	
    }	
    //代理上交班费,调用被代理学生的上交班费行为	
    public void giveMoney() {	
        stu.giveMoney();	
    }	
}


/**	
 * 测试类	
 */	
public class StaticProxyTest {	
    public static void main(String[] args) {	
        //被代理的学生张三,他的班费上交有代理对象monitor(班长)完成	
        Person zhangsan = new Student("张三");	
        	
        //生成代理对象,并将张三传给代理对象	
        Person monitor = new StudentsProxy(zhangsan);	
      	
        //班长代理上交班费	
        monitor.giveMoney();	
    }	
}


/**	
 * 学生代理类	
 */	
public class StudentsProxy implements Person{	
    //被代理的学生	
    Student stu;	
    public StudentsProxy(Person stu) {	
        // 只代理学生对象	
        if(stu.getClass() == Student.class) {	
            this.stu = (Student)stu;	
        }	
    }	
    //代理上交班费,调用被代理学生的上交班费行为	
    public void giveMoney() {	
        System.out.println("张三最近学习有进步!");	
        stu.giveMoney();	
    }	
}


可以看到,只需要在代理类中帮张三上交班费之前,执行其他操作(方法)就可以了。

这种操作,也是使用代理模式的一个很大的优点。最直白的就是在Spring中的面向切面编程(AOP),我们能在一个切点之前执行一些操作,在一个切点之后执行一些操作,这个切点就是一个个方法。

这些方法所在类肯定就是被代理了,在代理过程中切入了一些其他操作。


动态代理


public void giveMoney() {	
        beforeMethod();//调用被代理方法前加入处理方法	
        stu.giveMoney();	
}	
/**	
 * 创建Person接口	
 */	
public interface Person {	
     void giveMoney(); //上交班费	
}


public class Student implements Person {	
    private String name;	
    public Student(String name) {	
         = name;	
    }	
    	
    @Override	
    public void giveMoney() {	
        try {	
          //假设数钱花了一秒时间	
            Thread.sleep(1000);	
        } catch (InterruptedException e) {	
            e.printStackTrace();	
        }	
       System.out.println(name + "上交班费50元");	
    }	
}


public class MonitorUtil {	
    	
    private static ThreadLocal<Long> tl = new ThreadLocal<>();	
    	
    public static void start() {	
        tl.set(System.currentTimeMillis());	
    }	
    	
    //结束时打印耗时	
    public static void finish(String methodName) {	
        long finishTime = System.currentTimeMillis();	
        System.out.println(methodName + "方法耗时" + (finishTime - tl.get()) + "ms");	
    }	
}


public class StuInvocationHandler<T> implements InvocationHandler {	
    T target; //invocationHandler持有的被代理对象	
    public StuInvocationHandler(T target) {	
       this.target = target;	
    }	
    /**	
     * proxy:代表动态代理对象     method:代表正在执行的方法 args:代表调用目标方法时传入的实参	
     */	
    @Override	
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {	
        System.out.println("代理执行" +method.getName() + "方法");	
        //代理过程中插入监测方法,计算该方法耗时	
        MonitorUtil.start();	
        Object result = method.invoke(target, args);	
        MonitorUtil.finish(method.getName());	
        return result;	
    }	
}


测试类


public class ProxyTest {	
    public static void main(String[] args) {	

	
        //创建一个实例对象,这个对象是被代理的对象	
        Person zhangsan = new Student("张三");	

	
       //创建一个与代理对象相关联的InvocationHandler	
        InvocationHandler stuHandler = new StuInvocationHandler<Person>(zhangsan);	
        	
        //创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法	
        Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);	

	
       //代理执行上交班费的方法	
        stuProxy.giveMoney();	
    }	
}



总结一下: 上面的动态代理的例子,其实就是AOP的一个简单实现了,在目标对象的方法执行之前和执行之后进行了处理,对方法耗时统计。Spring的AOP实现其实也是用了Proxy和InvocationHandler这两个东西的。