代理理 设计模式的原理:
使用一个代理将对象包装起来, 然后用该代理对象取代原始象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
动态代理相比于静态代理的优点:
抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。(看完下面就能理解)
静态代理:
创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。
接口:(代理类和被代理类都需要implement接口)
public interface HelloInterface {
void sayHello();
}
被代理类:
public class Hello implements HelloInterface{
@Override
public void sayHello() {
System.out.println("代理类方法执行");
}
}
代理类:(这里直接new hello 也可以通过参数传入)
public class HelloProxy implements HelloInterface{
private HelloInterface helloInterface = new Hello();
@Override
public void sayHello() {
System.out.println("Before invoke sayHello" );
helloInterface.sayHello();
System.out.println("After invoke sayHello");
}
}
使用代理类:
被代理类被传递给了代理类HelloProxy,代理类在执行具体方法时通过所持用的被代理类完成调用。
public static void main(String[] args) {
HelloProxy helloProxy = new HelloProxy();
helloProxy.sayHello();
}
输出:
Before invoke sayHello
代理类方法执行
After invoke sayHello
动态代理:
动态代理步骤:
- 创建被代理的类以及接口
- 创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作
- 通过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建个 一个Subject 接口代理
RealSubject target = new RealSubject();
// Create a proxy to wrap the original implementation
DebugProxy proxy = new DebugProxy(target);
// Get a reference to the proxy through the Subject interface
Subject sub = (Subject) Proxy.newProxyInstance(
Subject.class.getClassLoader(),new Class[] { Subject.class }, proxy);
接口:(代理类和被代理类都需要implement接口)
public interface HelloInterface {
void sayHello();
}
被代理类:
public class Hello implements HelloInterface{
@Override
public void sayHello() {
System.out.println("代理类方法执行");
}
}
构建一个handler类来实现InvocationHandler接口:
public class ProxyHandler implements InvocationHandler{
private Object object;
public ProxyHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invoke " + method.getName());
method.invoke(object, args);
System.out.println("After invoke " + method.getName());
return null;
}
}
执行动态代理:
public static void main(String[] args) {
//就是把创建的这个类文件保存到本地,可以看到创建的是一个class文件,通过idea可以看到反编译过来的代码
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
HelloInterface hello = new Hello();
InvocationHandler handler = new ProxyHandler(hello);
HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);
proxyHello.sayHello();
}
输出:
Before invoke sayHello
代理类方法执行
After invoke sayHello
动态代理与AOP (Aspect Orient Programming)
前面介绍的Proxy和InvocationHandler,很难看出这种动态代理的优势,下面介绍一种更实用的动态代理机制
接口:
public interface Dog{
void info();
void run();
}
被代理类:
public class HuntingDog implements Dog{
public void info(){
System.out.println("我是一只猎狗");
}
public void run(){
System.out.println("我奔跑迅速");
}
}
模拟通用方法:
public class DogUtil{
public void method1(){
System.out.println("===== 模拟通用方法一=====");
}
public void method2(){
System.out.println("===== 模拟通用方法二=====");
}
}
构建一个handler类来实现InvocationHandler接口:
public class MyInvocationHandler implements InvocationHandler{
// 需要被代理的对象
private Object target;
public void setTarget(Object target){
this.target = target;}
// 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke 方法
public Object invoke(Object proxy, Method method, Object[] args)throws Exception{
DogUtil du = new DogUtil();
// 执行DogUtil 对象中的method1。 。
du.method1();
// 以target 作为主调来执行method 方法
Object result = method.invoke(target , args);
// 执行DogUtil 对象中的method2。 。
du.method2();
return result;
}
}
代理工厂生产:
public class MyProxyFactory{
//为指定target 生成动态代理对象
public static Object getProxy(Object target)throws Exception{
// 创建一个MyInvokationHandler 对象
MyInvokationHandler handler = new MyInvokationHandler();
// 为MyInvokationHandler 设置target 对象
handler.setTarget(target);
// 创建、并返回一个动态代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader()
, target.getClass().getInterfaces() , handler);
}
}
执行动态代理:
public class Test{
public static void main(String[] args)throws Exception{
// 创建一个原始的HuntingDog 对象,作为target
Dog target = new HuntingDog();
// 以指定的target 来创建动态代理
Dog dog = (Dog)MyProxyFactory.getProxy(target);
dog.info();
dog.run();
}
}
- 使用Proxy生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有太大的意义。通常都是为指定的目标对象生成动态代理
- 这种动态代理在AOP中被称为AOP代理,AOP代理可代替目标对象,AOP代理包含了目标对象的全部方法。但AOP代理中的方法与目标对象的方法存在差异:AOP 代理里的方法可以在执行目标方法之前、之后插入一些通用处理