代理模式概述:
作 用:保护被代理对象,通过被代理类的功能增加快速实现具有相同功能增强需求的被代理功能增强;
特 点:现实世界代理是委托人找代理人, 设计模式中是代理人调用委托人;
优 点:有利于框架的拓展增强被代理对象,解耦调用者与被调用者,提高代码的重用率;
使用场景:需要对被代理对象进行功能增强的时候使用,一般用于框架重用与多处业务逻辑;
典型案例:1,AOP切面编程:在一系列纵向的控制流程中,把那些相同的子流程提取成一个横向的面。
2,日志监控log4j;
代理模式实现方式:
静态代理:显式的申明被代理对象,代理类实现和被代理类一样的接口然后持有一个实现类,调用方法时调用代理类的方法,并可在前后进行增强;
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
动态代理:编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。
优 势:大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。
实现方式: JDK方式(需要被代理类实现接口),Cglib方式(本质是使用的继承方式实现动态代理);
静态代理实现:
//测试类
public class Test {
public static void main(String[] args){
/**静态代理:
* 在编译时就确定目标类是哪个时可使用;
* 缺点:调用者和实现者之间耦合(当下次不是人找房子,是公司找房子怎么办?),
* 在不同的业务中需要实现多个目标实现类的时候代码冗余高;*/
LianJiaBroker broker = new LianJiaBroker(new Mic());
broker.lookRoom();
}
}
//接口
package com.study.design.proxy.staticProxy;
/**
* modle人
*
* @author
*/
public interface Person {
/**姓名*/
String name = "小何";
/**年龄*/
Integer age = 24;
/**薪水*/
Integer salary = 3000;
/**工作*/
String work = "码农";
/**找房子*/
void lookRoom();
}
//被代理人
package com.study.design.proxy.staticProxy;
/**
* MIC
*
* @author
*/
public class Mic implements Person {
@Override
public void lookRoom() {
System.out.println("这套成都高新区的租金在2000以内的套一房屋不错");
}
}
//代理人
package com.study.design.proxy.staticProxy;
/**
* 链家经纪人
*
* @author
*/
public class LianJiaBroker implements Person {
private Person mustomer;
public LianJiaBroker(Person mustomer) {
this.mustomer = mustomer;
}
@Override
public void lookRoom() {
System.out.println("这里是我的出租房目录,任君挑选");
mustomer.lookRoom();
System.out.println("与房东见面,签订租房合同");
}
}
自己实现动态代理:
jdk方式
//接口:人需要找房子
package com.study.design.proxy.jdkProxy;
/**
* modle人
*
* @author
*/
public interface Person {
/**姓名*/
String name = "小何";
/**年龄*/
Integer age = 24;
/**薪水*/
Integer salary = 3000;
/**工作*/
String work = "码农";
/**找房子*/
void lookRoom();
}
//接口实现实现1
package com.study.design.proxy.jdkProxy;
/**
* MAC是高级开发工程师
*
* @author
*/
public class Mic1 implements Person {
@Override
public void lookRoom() {
System.out.println("MAC是高级开发工程师,热爱学习,租套一的房子,方便安静学习;");
}
}
//接口实现2
package com.study.design.proxy.jdkProxy;
/**
* MIC是高级技术专家
*
* @author
*/
public class Mic2 implements Person{
@Override
public void lookRoom() {
System.out.println("MIC是高级技术专家,热爱工作,只租五街的房子;生活即工作");
}
}
//动态代理实现
package com.study.design.proxy.jdkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 我是动态代理,我很高级
* @author
*/
public class JDKLianJiaBroker implements InvocationHandler {
private Person target;
public Object getInstance(Person target) throws Exception{
this.target = target;
Class<?> clazz = target.getClass();
//用来生成一个新的对象(字节码重组来实现)
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是链家高新区头号员工:我已经了解你租房的需求");
method.invoke(this.target,args);
System.out.println("安排签订租房合同");
return null;
}
}
//测试类
package com.study.design.proxy;
import com.study.design.proxy.jdkProxy.JDKLianJiaBroker;
import com.study.design.proxy.jdkProxy.Mic1;
import com.study.design.proxy.jdkProxy.Mic2;
import com.study.design.proxy.jdkProxy.Person;
import com.study.design.proxy.staticProxy.LianJiaBroker;
import com.study.design.proxy.staticProxy.Mic;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args){
/**动态代理:*/
try {
Person obj = (Person)new JDKLianJiaBroker().getInstance(new Mic1());
System.out.println(obj.getClass());
obj.lookRoom();
Person obj1 = (Person)new JDKLianJiaBroker().getInstance(new Mic2());
obj1.lookRoom();
} catch (Exception e) {
e.printStackTrace();
}
}
}
从以上的JDK动态代理实现方式我们可以发现重点类: Proxy、 InvocationHandler
//代理对象创建:Proxy.newProxyInstance()
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 查找或生成指定的代理类。
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* 使用指定的调用处理程序调用其构造函数。
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
//代理对象返回的Object 是什么呢?我们解码出来看其内容是新生成了一个对象$Proxy0
public final void lookRoom() throws{
try {
h是什么呢?Proxy -- InvocationHandler
m3 : lookRoom()方法
this.h.invoke(this, m3, null);
return;
} catch (Error|RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
m3 = Class.forName("com.study.design.proxy.jdkProxy.Person").getMethod("lookRoom", new Class[0]);
从源码我们可以看出,主要就是Proxy完成了新的类$Proxy的初始化创建过程;因此我们要自己实现一个代理类只需要实现一个$Proxy0.class的创建和类加载就好了;
自己实现代理
package com.study.design.proxy.myProxy;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 我的类加载器
*
* @author
*/
public class MyClassLoader extends ClassLoader{
private File classPathFile;
public MyClassLoader(){
String classPath = MyClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.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){
e.printStackTrace();
}finally {
if(null != in){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
package com.study.design.proxy.myProxy;
import java.lang.reflect.Method;
/**
* 实现动态代理需实现接口
*
* @author
*/
public interface MyInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
package com.study.design.proxy.myProxy;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* 我是谁
*
* @author
*/
public class MyProxy {
public static final String ln = "\r\n";
public static Object newProxyInstance(MyClassLoader classLoader,Class<?> [] interfaces,MyInvocationHandler h){
try {
//1、动态生成源代码.java文件
String src = generateSrc(interfaces);
//2、Java文件输出磁盘
String filePath = MyProxy.class.getResource("").getPath();
System.out.println(filePath);
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//3、把生成的.java文件编译成.class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manage.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
task.call();
manage.close();
//4、编译生成的.class文件加载到JVM中来
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
f.delete(); //删除文件
//5、返回字节码重组以后的新的代理对象
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.study.design.proxy.myProxy;" + ln);
sb.append("import com.study.design.proxy.staticProxy.Person;" + ln);
sb.append("import java.lang.reflect.Method;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
//属性
sb.append("MyInvocationHandler h;" + ln);
//构造器
sb.append("public $Proxy0(MyInvocationHandler h) { " + ln);
sb.append("this.h = h;");
sb.append("}" + ln);
//循环设置方法
for (Method m : interfaces[0].getMethods()){
sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
sb.append("try{" + ln);
sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
sb.append("this.h.invoke(this,m,null);" + ln);
sb.append("}catch(Throwable e){" + ln);
sb.append("e.printStackTrace();" + ln);
sb.append("}");
sb.append("}");
}
sb.append("}" + ln);
return sb.toString();
}
}