バックグラウンド
プロキシモードは構造モードに属しており、開発においてよく使われるデザインモードの一つでもありますが、今回はプロキシモードをより早く理解していただくために、以下のプロキシモードの書き方について説明していきます。これには、動的プロキシを自分で記述する方法も含まれます。
静的プロキシ
package com.example.proxy.staticProxy;
public interface IPerson {
String findJob();
}
package com.example.proxy.staticProxy;
public class Customer implements IPerson{
@Override
public String findJob() {
return "工作要求:高薪,双休,福利好,事少,压力小";
}
}
package com.example.proxy.staticProxy;
public class CustomFather implements IPerson{
private IPerson iPerson;
//客户老爸知道他儿子的要求
public CustomFather(IPerson iPerson) {
this.iPerson = iPerson;
}
public static void main(String[] args) {
CustomFather bossProxy=new CustomFather(new Customer());
bossProxy.findJob();
}
@Override
public String findJob() {
before();
System.out.println(iPerson.findJob());
after();
return null;
}
private void after() {
System.out.println("找到了,结束....");
}
private void before() {
System.out.println("客户老爸开始给儿子物色工作....");
}
}
package com.example.proxy.staticProxy;
public class StaticProxyTest {
public static void main(String[] args) {
//静态代理也可以使用,只是代理的对象个数很少,如果有其他人也要找工作并不适配,且客户老爸这个类也要经常进行修改
CustomFather customFather = new CustomFather(new Customer());
customFather.findJob();
}
}
JDK動的プロキシ
package com.example.proxy.jdkProxy;
public interface IPerson {
String findJob();
}
package com.example.proxy.jdkProxy;
public class Customer implements IPerson {
@Override
public String findJob() {
return "工作要求:高薪,双休,福利好,事少,压力小";
}
}
package com.example.proxy.jdkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler {
private IPerson iPerson;
public IPerson getProxy(IPerson iPerson) {
this.iPerson = iPerson;
Class clz = iPerson.getClass();
return (IPerson) Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
System.out.println(method.invoke(this.iPerson, args));
after();
return null;
}
private void after() {
System.out.println("找到了,结束....");
}
private void before() {
System.out.println("客户老爸开始给儿子物色工作....");
}
}
package com.example.proxy.jdkProxy;
public class JdkProxyTest {
public static void main(String[] args) {
//动态代理,增加客户需求接口,代理类不需要经常变化,单要比cglib的动态代理性能要差一点
JdkProxy jdkProxy = new JdkProxy();
IPerson iPerson = jdkProxy.getProxy(new Customer());
iPerson.findJob();
//使用jdk的工具生成代理类的字节码文件,然后我们可以安装jad反编译工具,进行反编译
byte bytes[]=ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{
IPerson.class});
try {
FileOutputStream fileOutputStream=new FileOutputStream(new File("d://$Proxy.class"));
fileOutputStream.write(bytes);
fileOutputStream.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Jadダウンロードファイルアドレス:https://varaneckas.com/jad/
cglib動的プロキシ
package com.example.proxy.cglibProxy;
public class Customer {
public String findJob() {
return "工作要求:高薪,双休,福利好,事少,压力小";
}
}
package com.example.proxy.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 implements MethodInterceptor {
public Object getProxy(Class<?> clz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
System.out.println(methodProxy.invokeSuper(o,objects));
after();
return null;
}
private void after() {
System.out.println("找到了,结束....");
}
private void before() {
System.out.println("客户老爸开始给儿子物色工作....");
}
}
package com.example.proxy.cglibProxy;
public class CglibProxyTest {
public static void main(String[] args) {
// cglib的动态代理推荐使用,因为性能比jdk都好
// 注意custom类中不能用final修饰的方法
CglibProxy cglibProxy = new CglibProxy();
Customer customer = (Customer) cglibProxy.getProxy(new Customer().getClass());
customer.findJob();
}
}
jdk動的プロキシを模倣して動的プロキシを自ら実現する
基礎となる実装に慣れるのが簡単
package com.example.proxy.customProxy;
public interface IMyPerson {
String findJob();
}
package com.example.proxy.customProxy;
import java.io.*;
public class MyClassLoader extends ClassLoader {
private File classFilePath;
public MyClassLoader() {
this.classFilePath = new File(MyClassLoader.class.getResource("").getPath());
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classname = MyClassLoader.class.getPackage().getName() + "." + name;
if (classFilePath != null) {
File file = new File(classFilePath, name.replaceAll("\\.","/") + ".class");
if (file.exists()) {
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte buff[] = new byte[1024];
int len;
while ((len = fis.read(buff)) != -1) {
bos.write(buff, 0, len);
}
return defineClass(classname, bos.toByteArray(), 0, bos.size());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
return null;
}
}
package com.example.proxy.customProxy;
import com.example.proxy.jdkProxy.IPerson;
public class MyCustomer implements IMyPerson {
@Override
public String findJob() {
return "工作要求:高薪,双休,福利好,事少,压力小";
}
}
package com.example.proxy.customProxy;
import java.lang.reflect.Method;
public interface MyInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
package com.example.proxy.customProxy;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class MyProxy {
public static Object newProxyInstance(MyClassLoader loader,
Class<?>[] interfaces,
MyInvocationHandler h)
throws IllegalArgumentException {
//Step1 生成代理类的java文件
String originCode = generate(interfaces);
//System.out.println(originCode);
//Step2 把生成代理类的java文件写到磁盘$Proxy0.java
String path = MyProxy.class.getResource("").getPath();
File file = new File(path + "$Proxy0.java");
try {
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(originCode);
fileWriter.flush();
fileWriter.close();
//Step3 将java文件编译成class文件$Proxy0.class
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
Iterable iterable = manager.getJavaFileObjects(file);
JavaCompiler.CompilationTask compilationTask = compiler.getTask(null, manager, null, null, null, iterable);
compilationTask.call();
manager.close();
//Step4 将class文件加载到jvm中
Class clz = loader.findClass("$Proxy0");
Constructor constructor = clz.getConstructor(MyInvocationHandler.class);
//Step5 将生成java文件删除
file.delete();
return constructor.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String generate(Class<?>[] interfaces) {
String ln = "\r\n";
StringBuffer sb = new StringBuffer();
sb.append("package com.example.proxy.customProxy;" + ln);
sb.append("import java.lang.reflect.*;" + ln);
sb.append("import com.example.proxy.customProxy.IMyPerson;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + " {" + ln);
sb.append("private MyInvocationHandler h;" + ln);
sb.append(" public $Proxy0(MyInvocationHandler invocationhandler)\n" +
" {
\n" + ln +
" this.h=invocationhandler;\n" + ln +
" }" + ln);
//方法由于我们只有一个,就写死了是一个,如果多个,可以用循环
sb.append("public final String findJob()\n" + ln +
" {
\n" + ln +
" try\n" + ln +
" {
\n" + ln +
" Method m = com.example.proxy.customProxy.IMyPerson.class.getMethod(\"findJob\",new Class[]{});"+ ln +
" return (String)this.h.invoke(this, m, new Object[]{});\n" + ln +
" }\n" + ln +
" catch(Error _ex) { " + ln +
"throw new UndeclaredThrowableException(_ex);" + ln +
"}\n" + ln +
" catch(Throwable throwable)\n" + ln +
" {
\n" +
" throw new UndeclaredThrowableException(throwable);\n" + ln +
" }\n" + ln +
" }" + ln);
sb.append("}" + ln);
return sb.toString();
}
private static String toLowerFirstCase(String src){
char [] chars = src.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
private static Map<Class,Class> mappings = new HashMap<Class, Class>();
static {
mappings.put(int.class,Integer.class);
}
private static String getReturnEmptyCode(Class<?> returnClass){
if(mappings.containsKey(returnClass)){
return "return 0;";
}else if(returnClass == void.class){
return "";
}else {
return "return null;";
}
}
private static String getCaseCode(String code,Class<?> returnClass){
if(mappings.containsKey(returnClass)){
return "((" + mappings.get(returnClass).getName() + ")" + code + ")." + returnClass.getSimpleName() + "Value()";
}
return code;
}
private static boolean hasReturnValue(Class<?> clazz){
return clazz != void.class;
}
}
package com.example.proxy.customProxy;
import java.lang.reflect.Method;
public class MyProxyProxy implements MyInvocationHandler{
private IMyPerson iMyPerson;
public IMyPerson getProxy(IMyPerson iMyPerson) {
this.iMyPerson = iMyPerson;
Class<?> clz=iMyPerson.getClass();
return (IMyPerson) MyProxy.newProxyInstance(new MyClassLoader(),clz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
System.out.println(method.invoke(this.iMyPerson, args));
after();
return null;
}
private void after() {
System.out.println("找到了,结束....");
}
private void before() {
System.out.println("客户老爸开始给儿子物色工作....");
}
}
package com.example.proxy.customProxy;
public class MyProxyProxyTest {
public static void main(String[] args) {
//动态代理,增加客户需求接口,代理类不需要经常变化,单要比cglib的动态代理性能要差一点
MyProxyProxy myProxyProxy = new MyProxyProxy();
IMyPerson iPerson = myProxyProxy.getProxy(new MyCustomer());
iPerson.findJob();
}
}