代理模式
代理模式分为静态代理和动态代理,动态代理又分为jdk动态代理和CGLIB动态代理,动态代理的主要目的就是在不改变原有代码的情况下,对原代码的功能进行增强,其中Spirng的Aop ,rpc框架远程调用以及开发中dao层接口调用方法时。
1.静态代理
实现方式:目标对象和代理对象实现相同接口
缺点:接口改变时,目标对象和代理对象都需要维护
定义一个抽象的对象
package com.sj.staticproxy;
public interface Add {
void save();
}
目标对象对抽象对象做具体实现
package com.sj.staticproxy;
public class Target implements Add {
@Override
public void save() {
System.out.println("添加数据完成");
}
}
创建代理对象,也对抽象对象进行具体的实现,同时构造函数有对目标对象的引用
ackage com.sj.staticproxy;
public class Proxy implements Add{
private Target target;
public Proxy(Target target) {
this.target=target;
}
@Override
public void save() {
System.out.println("准备添加数据");
target.save();
System.out.println("关机下班");
}
}
编写测试类,进行代码测试
public class Test {
public static void main(String[] args) {
Proxy proxy = new Proxy(new Target());
proxy.save();//准备添加数据,数据添加完成 关机下班
}
}
2.jdk动态代理
jdk动态代理是基于接口的动态代理,也是java虚拟机默认的代理方式,具体实现是依赖反射机制,需要目标对象实现一个接口
定义一个接口
package com.sj.jdkproxy;
public interface User {
String sing(String s);
void dance();
}
定义目标对象实现接口
package com.sj.jdkproxy;
public class Target implements User {
@Override
public String sing(String s) {
System.out.println("我会唱歌");
return s;
}
@Override
public void dance() {
System.out.println("我会跳舞");
}
}
使用Proxy的newProxyInstance方法,创建代理对象
package com.sj.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy {
public static void main(String[] args) {
Target target = new Target();//创建目标对象
newProxyInstance的三个参数:
第一个:目标对象的类加载器
第二个:目标对象的接口数组
第三个:InvocationHandler接口是proxy代理实例调用处理程序实现的一个接口,每一个proxy 代理实例都有一个关联的调用处理程序,在代理实例调用方法时,方法调用被编码分派到调用处理程序 invoke方法。
User user = (User)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
invoke方法的三个参数:
第一个:调用这个方法的代理实例
第二个:要调用的方法
第三个:方法调用时所需要的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj=null;
if ("sing".equals(method.getName())){
System.out.println("前置");
obj = method.invoke(target,args);
System.out.println("后置");
}else {
method.invoke(target,args);
}
return obj;
}
});
String s = user.sing("中国");
System.out.println(s);
user.dance();
/*输出结果:前置
我会唱歌
后置
中国
我会跳舞*/
}
}
3.基于父类的动态代理 CGLib
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
创建一个需要被代理的类,也就是父类,底层会通过字节码技术创建这个类的子类,实现动态代理。
package com.sj.cglibProxy;
public class Target {
public void say(){
System.out.println("hello");
}
public void listen(){
System.out.println("listen to me...");
}
}
使用Enhancer 的create方法创建代理对象
package com.sj.cglibproxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy {
public static void main(String[] args) {
Target target= new Target();//创建目标对象
Target target1 =(Target)Enhancer.create(target.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("前置");
method.invoke(target,args);
System.out.println("后置");
return null;//用于返回带返回值方法的返回值
}
});
target1.say();
target1.listen();
/*输出结果:前置
hello
后置
前置
listen to me ,,,
后置*/
}
}