代理模式
2019-06-19 本文已影响0人
降龙_伏虎
1.概念
代理模式(Proxy Pattern) 是指为其它对象提供一种代理,以控制这个对象的访问,
代理对象在客户端和目标对象之间起到中介作用,
属于结构型设计模式
2.静态代理
"非专业"中介,只能为特定对象进行代理,如父母代理儿子找对象;
代码中指为某个特定的对象的特定方法进行代理,
不具有通用性,以及动态切换的能力
/**
* Description:儿子类(被代理对象)
*
* @date 2019-05-08 19:39
*/
public class Son{
/**
* Description:找对象要求
* @Date 2019-05-08 19:40
* @Param []
* @return java.lang.String
**/
public String findLove(){
return "租房要求:女的";
}
}
/**
* Description:父亲类(代理人)
*
* @date 2019-05-08 19:41
*/
public class Father {
private Son son;
public Father(Son son) {
this.son = son;
}
public String helpFindLove(){
System.out.println("父亲帮儿子找对象开始");//此处可进行特殊处理
String s = son.findLove();
System.out.println("儿子找对象要求:"+s);
System.out.println("父亲帮儿子找对象结束");//此处可进行特殊处理
return s;
}
}
/**
* Description:静态代理测试
*
* @date 2019-05-08 19:47
*/
public class Test {
public static void main(String[] args) {
Father father = new Father(new Son());
father.helpFindLove();
}
}
3.动态代理
"专业"中介,能为所有对象进行代理,如婚介所;
具有通用性,以及动态切换的能力
3.1 JDK 动态代理
/**
* Description:人接口
*
* @date 2019-05-09 19:33
*/
public interface Person {
void findLove();
}
/**
* Description:女孩类
*
* @date 2019-05-09 19:32
*/
public class Girl implements Person{
@Override
public void findLove(){
System.out.println("要求:是男的");
}
}
/**
* Description:媒婆
*
* @date 2019-05-09 19:36
*/
public class MeiPo implements InvocationHandler {
//被代理对象
private Person target;
//获取JDK代理
public Object getInstance(Person person){
this.target = person;
Class<?> clazz = target.getClass();
//根据被代理对象信息获取代理对象(被代理对象被代理对象"包裹")
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
befor();
Object obj = method.invoke(this.target,args);
after();
return obj;
}
private void befor(){
System.out.println("代理前置操作...");
}
private void after(){
System.out.println("代理后置操作...");
}
}
/**
* Description:JDKd动态代理测试类
*
* @date 2019-05-09 19:44
*/
public class Test {
public static void main(String[] args) {
try {
Person obj = (Person)new MeiPo().getInstance(new Girl());
obj.findLove();
} catch (Exception e) {
e.printStackTrace();
}
}
}
原理
将被代理对象做相关特殊包装后 通过"动态生成字节码"生成一个新的"被包装"的类
/**
* 通道JDK代理生成的类
* ① 新的类继承Proxy
* ② 新的类实现Person接口
*
*
**/
public final class $Proxy0 extends Proxy implements Person {
....
//被代理对象的方法
public final void findLove() throws {
try {
//执行媒婆对象的invoke方法&将当前对象传入媒婆
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
....
}
手工模拟JDK动态代理
/**
* Description:人接口
*
* @date 2019-05-09 19:33
*/
public interface Person {
void findLove();
}
/**
* Description:女孩类
*
* @date 2019-05-09 19:32
*/
public class Girl implements Person{
@Override
public void findLove(){
System.out.println("要求:是男的");
}
}
/**
* Description:代理
*
* @date 2019-05-13 19:53
*/
public class SkyMeiPo implements SkyInvocationHandler{
//被代理对象
private Person target;
//获取JDK代理
public Object getInstance(Person person){
this.target = person;
Class<?> clazz = target.getClass();
//根据被代理对象信息获取代理对象(被代理对象被代理对象"包裹")
return SkyProxy.newProxyInstance(new SkyClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
befor();
Object obj = method.invoke(this.target,args);
after();
return obj;
}
private void befor(){
System.out.println("代理前置操作...");
}
private void after(){
System.out.println("代理后置操作...");
}
}
/**
* Description:
*
* @date 2019-05-13 19:50
*/
public class SkyProxy {
private static final String LN = "\r\n";
@CallerSensitive
public static Object newProxyInstance(SkyClassLoader loader,
Class<?>[] interfaces,
SkyInvocationHandler h)
throws IllegalArgumentException {
try {
//1.动态生成代码
String src = generateSrc(interfaces);
System.out.println(src);
//2.java文件输出到磁盘
String filePath = SkyProxy.class.getResource("").getPath();
File f = new File(filePath+"$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//编译代码
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//获取系统编译器
StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manager.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null,manager,null,null,null,iterable);
task.call();
manager.close();
Class proxyClass = loader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(SkyInvocationHandler.class);
return c.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?>[] interfaces) {
/*用代码写代码*/
StringBuffer sb = new StringBuffer();
//引包
sb.append("package com.sky.designpattern.proxy.dynamicproxy.custom;").append(LN);
sb.append("import com.sky.designpattern.proxy.dynamicproxy.jdk.Person;").append(LN);
sb.append("import java.lang.reflect.Method;").append(LN);
//类头
sb.append("public class $Proxy0 implements ").append(interfaces[0].getName()).append("{").append(LN);
//声明变量
sb.append("SkyInvocationHandler h;").append(LN);
//构造方法
sb.append("public $Proxy0(SkyInvocationHandler h){").append(LN);
sb.append("this.h=h;").append(LN);
sb.append("}").append(LN);
//反射生成方法
for(Method m:interfaces[0].getMethods()){
sb.append("public ").append(m.getReturnType().getName()).append(" ").append(m.getName()).append("(){").append(LN);
sb.append("try{").append(LN);
sb.append("Method m = ").append(interfaces[0].getName()).append(".class.getMethod(\""+m.getName()+"\",new Class[]{});").append(LN);
sb.append("this.h.invoke(this,m,null);").append(LN);
sb.append("}catch(Throwable e){").append(LN);
sb.append("e.printStackTrace();").append(LN);
sb.append("}").append(LN);
sb.append("}").append(LN);
}
sb.append("}");
return sb.toString();
}
}
public interface SkyInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
public class SkyClassLoader extends ClassLoader{
private File classPathFile;
public SkyClassLoader() {
String classPath = SkyClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = SkyClassLoader.class.getPackage().getName()+"."+name;
if(classPathFile !=null){
File classFile = new File(classPathFile,name.replaceAll("\\.","/")+".class");
if(classFile.exists()){
FileInputStream in =null;
ByteArrayOutputStream out = null;
try{
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte [] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1){
out.write(buff,0,len);
}
return defineClass(className,out.toByteArray(),0,out.size());
}catch (Exception e){
}
}
}
return null;
}
}
3.2cglib动态代理
3.2.1与JDK的区别
1.JDK动态代理是通过反射实现,而cglib是通过生成被代理类的子类
来实现
2.cglib因为没用到反射效率更高
3.不可代理 final类
4.被代类不需要实现统一接口
3.2.2代码实现
/**
* Description:被代理类
*
* @date 2019-05-22 20:11
*/
public class Persion {
public void findLove(){
System.out.println("肤白貌美大长腿");
}
}
/**
* Description:代理类
*
* @date 2019-05-22 20:01
*/
public class MeiPo implements MethodInterceptor {
public Object getInstance(Class<?> clazz) throws Exception{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object object = methodProxy.invokeSuper(o,objects);
after();
return object;
}
private void before(){
System.out.println("before");
}
private void after(){
System.out.println("after");
}
}
/**
* Description:测试类
*
* @date 2019-05-22 20:01
*/
public class Test {
public static void main(String[] args) {
try {
Persion persion = (Persion) new MeiPo().getInstance(Persion.class);
persion.findLove();
} catch (Exception e) {
e.printStackTrace();
}
}
}