什么是代理?
从字面意思来看,代理比较好理解,无非就是代为处理的意思。举个例子,现在哪吒有女助理了,所以很多事情都不用我自己去处理了,比如说去银行排队取钱,那么我就可以叫我的女助理去代替我取钱并交给我,那么我自己就可以去干其他的事情,那么此时女助理就充当了代理的作用,代替我取钱。
优点:
1.增强目标对象。可以在执行目标对象方法的前后或者其他地方加上验证、日志等等代码;(Spring框架中的AOP)
2.将调用对象和被调用对象分离,一定程度上降低了耦合度。扩展性好;
3.保护目标对象;
4.职责清晰。目标对象就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成,附带的结果就是编程简洁清晰。
缺点:
1.对象与对象调用之间增加了一层代理,可能会导致执行的速度变慢;
2.实现代理的代码有时会很复杂,添加了额外的工作量;
3.增加系统的复杂度。
代理模式有二类实现方式:
静态代理
代理类在程序运行前就编译好,因此称为静态代理。代理对象和被代理对象都要实现相同的接口或者继承相同的父类(除Object之外),一旦接口或者父类添加、修改方法,子类都要统一更改,违背开闭原则,因此静态代理具有一定的局限性,所以静态代理的实现有二种实现方式:
-
继承
我们假设一个场景,现在有个处理订单的业务,我们需要在处理订单方法前加日志记录怎么实现?
//公共接口 public interface Utils { void operate(); } //处理日志 public class LogBusiness implements Utils { @Override public void operate() { System.out.println("记录日志"); } } //处理订单方法 public class OmsBusiness extends LogBusiness implements Utils { @Override public void operate() { //因为这里继承了LogBusiness所以这里调用父类的operate方法就可以记录日志 super.operate(); System.out.println("处理订单"); } } //测试方法 public class Test { public static void main(String[] args) { OmsBusiness oms = new OmsBusiness(); oms.operate(); } } //结果 记录日志 处理订单
这时候老板让在记录下时间呢?
//处理时间 public class TimeBusiness implements Utils { @Override public void operate() { System.out.println("记录时间"); } } //处理日志,这里继承处理时间类。 public class LogBusiness extends TimeBusiness implements Utils { @Override public void operate() { //因为这里继承了TimeBusiness所以这里调用父类的operate方法就可以记录时间 super.operate(); System.out.println("记录日志"); } } //结果 记录时间 记录日志 处理订单
我们是先记录了时间在记录了日志,这时候老板让我们先记录日志在记录时间呢?
public void operate() { super.operate(); System.out.println("记录日志"); }
根据叠加业务及处理顺序不同,分别要创建不同的子类,这样就会造成类爆炸的问题还有代码冗余,就会有很多类来处理这种辅助功能,不好管理。但是聚合可以避免这个问题。
-
聚合
我们开看下通过聚合的方式怎么解决上边的问题。
//公共接口 public interface Utils { void operate(); } //处理日志 public class LogBusiness implements Utils { @Override public void operate() { System.out.println("记录日志"); } } //处理时间 public class TimeBusiness implements Utils { @Override public void operate() { System.out.println("记录时间"); } } //处理订单 public class OmsBusiness implements Utils { @Override public void operate() { System.out.println("处理订单"); } } //代理对象 public class OmsBusinessProxy implements Utils { private OmsBusiness omsBusiness; public OmsBusinessProxy(OmsBusiness omsBusiness) { this.omsBusiness = omsBusiness; } //在这里就可以调整增加逻辑的顺序 @Override public void operate() { TimeBusiness time = new TimeBusiness(); LogBusiness log = new LogBusiness(); time.operate(); log.operate(); omsBusiness.operate(); } } //测试方法 public class Test { public static void main(String[] args) { Utils oms = new OmsBusinessProxy(new OmsBusiness()); oms.operate(); } } //结果 记录时间 记录日志 处理订单
很显然,聚合实现代理方式比继承代理方式更为灵活,代理之间可以互相组合,互相传递。
但是又问题来了,这个是处理订单的业务逻辑的增强,那么现在又有处理库存等等的业务逻辑需要增强,那么就需要每个业务逻辑增加一个代理类,代理类仍然会爆炸。可以通过动态代理来解决这个问题。
动态代理
上边说到的静态代理都有一个致命的类爆炸问题,那动态代理怎么解决呢?我们大胆的猜想下能不能不创建Java类用代码实现动态创建?想想应该是可以的,为什么呢?因为Java类文件也是字符串,我们只是用代码编写了这个字符串,然后生成.class文件然后再生成class对象最后通过反射实现生成Java对象,有思路了那就开始干。
//接口
public interface Person {
void eat();
}
//动态生成类对象
public class MyObject {
private static final String ENTER = "\r\n";
private static final String PAKAGE = MyObject.class.getPackage().toString()+";";
private static final String CLASS_NAME = "$Proxy";
//防止并发产生相同文件名
private static final AtomicInteger NUMBER= new AtomicInteger(0);
public static void main(String[] args) throws Exception {
//生成Java文件
String className = CLASS_NAME+NUMBER.getAndIncrement();
String javaString = createJavaString(new Class<?>[]{Person.class}, className);
String parentPath = MyObject.class.getResource("").getPath();
File file = new File(parentPath,className+".java" );
FileWriter writer = new FileWriter(file);
writer.write(javaString);
writer.flush();
writer.close();
//编译成class文件
JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
task.call();
standardFileManager.close();
//通过反射创建实例,CLClassLoader这个目前不用管就是生成class对象的工具,这里是先把.class文件转成byte字节码然后生成class对象
Class<?> aClass = new CLClassLoader().findClass(className);
Person instance = (Person) aClass.newInstance();
instance.eat();
}
//通过StringBuffer拼接代码
private static String createJavaString(Class<?>[] interfaces , String className){
StringBuffer buffer = new StringBuffer();
buffer.append(PAKAGE+ENTER);
StringBuffer interfaceString= new StringBuffer();
int length= interfaces.length;
for (int i = 0; i<length ; ++i){
interfaceString.append(interfaces[i].getName());
if (i!=length-1){
interfaceString.append(",");
}
}
buffer.append("public final class ");
buffer.append(className);
buffer.append(" implements ");
buffer.append(interfaceString);
buffer.append(" {"+ENTER);
buffer.append("public "+className+"() {}"+ENTER);
for (int i =0 ;i < length;++i){
Class<?> clazz= interfaces[i];
Method[] methods = clazz.getMethods();
for (Method method : methods){
String returnTypeString = method.getReturnType().getName();
int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers)){
buffer.append("public");
}else if (Modifier.isPrivate(modifiers)){
buffer.append("private");
}else if (Modifier.isProtected(modifiers)){
buffer.append("protected");
}
buffer.append(" final "+returnTypeString+" "+ method.getName()+"(" + "){"+ ENTER);
buffer.append("try{"+ENTER);
buffer.append("System.out.println(\"dynamic object!\");"+ENTER);
buffer.append("}catch(Throwable e){"+ENTER);
buffer.append("e.printStackTrace();"+ENTER);
buffer.append("}"+ENTER);
if (!"void".equals(returnTypeString)){
buffer.append("return null;"+ENTER);
}
buffer.append("}"+ENTER);
}
}
buffer.append("}");
return buffer.toString();
}
}
//ClassLoader工具类
public class CLClassLoader extends ClassLoader {
private File classPathFile;
public CLClassLoader(){
String classPath = CLClassLoader.class.getResource("").getPath();
this.classPathFile= new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = CLClassLoader.class.getPackage().getName()+"."+name;
if (classPathFile!= null ){
File classFile = new File(classPathFile, name.replace("\\.", "/") + ".class");
if (classFile.exists()){
FileInputStream inputStream =null;
ByteArrayOutputStream outputStream = null;
try{
inputStream=new FileInputStream(classFile);
outputStream= new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len=inputStream.read(bytes))!=-1){
outputStream.write(bytes,0,len);
}
return defineClass(className,outputStream.toByteArray(),0,outputStream.size());
}catch (Exception e){
e.printStackTrace();
}finally {
if (inputStream!= null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return super.findClass(name);
}
}
//生成的文件$Proxy0.java
package com.donny.erp.proxy.mydynamicobject;
public final class $Proxy0 implements com.donny.erp.proxy.mydynamicobject.Person {
public $Proxy0() {}
public final void eat(){
try {
System.out.println("dynamic object!");
} catch(Throwable e){
e.printStackTrace();
}
}
}
//生成的文件$Proxy0.class
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.donny.erp.proxy.mydynamicobject;
public final class $Proxy0 implements Person {
public $Proxy0() {
}
public final void eat() {
try {
System.out.println("dynamic object!");
} catch (Throwable var2) {
var2.printStackTrace();
}
}
}
可以看到这里我们是能成功的通过代码的形式生成类对象并且正常的执行eat方法。但是我们的方法体中写死了业务逻辑代码打印了"dynamic object!",那么怎么实现动态业务呢?我们先来看看jdk的动态代理是怎么实现的。
//接口
public interface Utils {
public void operate();
}
//目标对象
public class SourceObject implements Utils{
@Override
public void operate() {
System.out.println("处理订单");
}
}
//invocationhandler实现类
public class TimeInvocationHandler implements InvocationHandler {
private Object source;
public TimeInvocationHandler(Object source) {
this.source = source;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强
System.out.println("处理时间");
//执行目标对象的方法
Object invoke = method.invoke(source, args);
return invoke;
}
public Object createObject(){
Class<?> aClass = source.getClass();
//生成代理对象
Object o = Proxy.newProxyInstance(aClass.getClassLoader(), aClass.getInterfaces(), this);
return o;
}
}
//测试方法
public class Test {
public static void main(String[] args) {
//保存代理对象到磁盘
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
TimeInvocationHandler handler = new TimeInvocationHandler(new SourceObject());
Utils o = (Utils)handler.createObject();
o.operate();
}
}
可以看到创建代理对象就这一行代码。
Object o = Proxy.newProxyInstance(aClass.getClassLoader(), aClass.getInterfaces(), this);
这个方法和我们的对比差了一个参数,InvocationHandler的实现类,InvocationHandler接口只有一个invoke方法,可以看到增强逻辑都是在这个方法中执行的。那么也就是说我们在代理对象中执行传进来的InvocationHandler实现类的invoke方法就可以实现增强逻辑,看看JDK是怎么做的?
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{
private static final Class<?>[] constructorParams = { InvocationHandler.class };
//这里我只copy了重要的代码
//这个其实和我们上边实现逻辑的类似(但是实现方式不同,我们是先生成文件再加载为class,JDK是生成byte[]字节再加载成class,当然JDK的实现更快),只是它多了有一个InvocationHandler为参数的构造函数,并且方法全部都调用了InvocationHandler.invoke方法。下边可以看生成的反编译下class文件
Class<?> cl = getProxyClass0(loader, intfs);
//拿到一个InvocationHandler参数的构造函数的类对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
//通过构造函数的类对象反射出对象
return cons.newInstance(new Object[]{h});
}
//代理对象.class文件
public final class $Proxy0 extends Proxy implements Utils {
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final void operate() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
}
/*
这里说下面试会问到为什么JDK的动态代理只能代理基于接口的目标类。看到上边反编译的.class文件就可以解释这个问题了。
首先JDK代理会默认继承Proxy,其次Java是单继承。所以只能代理基于接口的目标类。
再看下operate()方法,里边其实就是执行了InvocationHandler.invoke,其实就是我们实现的InvocationHandler接口。
这样看下来还是挺简单的吧。我们继续把下边代码看了。
*/
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {
return proxyClassCache.get(loader, interfaces);
}
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
//查询缓存
Object cacheKey = CacheKey.valueOf(key, refQueue);
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
//创建
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
//返回
while (true) {
if (supplier != null) {
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
}
//重点 = subKeyFactory.apply(key, parameter)
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
//校验接口
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null;
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
//非public接口,代理类的包名与接口的包名相同
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
//代理名称
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//创建字节数据
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//调用底层native方法生成class对象
return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
知道JDK实现逻辑接下来我们自己实现下动态业务的动态代理吧
//接口
public interface Person {
void eat();
String call(String name);
}
//测试使用目标类
class Donny implements Person {
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public String call(String name) {
return name;
}
}
//自定义InvocationHandler
public interface CLInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
public class CLProxy {
private static final String ENTER = "\r\n";
private static final String PAKAGE = CLProxy.class.getPackage().toString()+";";
private static final String CLASS_NAME = "$Proxy";
//防止并发产生相同文件名
private static final AtomicInteger NUMBER= new AtomicInteger(0);
public static Object newProxyInstance(CLClassLoader classLoader, Class<?>[] interfaces,CLInvocationHandler h) throws Exception{
String className = CLASS_NAME+NUMBER.getAndIncrement();
//遍历所有的接口生成java 文件
String javaString = createJavaString(interfaces, className);
String parentPath = CLProxy.class.getResource("").getPath();
File file = new File(parentPath,className+".java" );
FileWriter writer = new FileWriter(file);
writer.write(javaString);
writer.flush();
writer.close();
//编译
JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
task.call();
standardFileManager.close();
//创建实例
Class<?> aClass = classLoader.findClass(className);
Constructor<?> constructor = aClass.getConstructor(CLInvocationHandler.class);
Object instance = constructor.newInstance(h);
//file.delete();
return instance;
}
/**
* 生成java 文件
* @param interfaces
* @return
*/
private static String createJavaString(Class<?>[] interfaces , String className){
StringBuffer buffer = new StringBuffer();
buffer.append(PAKAGE+ENTER);
buffer.append("import java.lang.reflect.Method;"+ ENTER);
StringBuffer interfaceString= new StringBuffer();
int length= interfaces.length;
for (int i = 0; i<length ; ++i){
interfaceString.append(interfaces[i].getName());
if (i!=length-1){
interfaceString.append(",");
}
}
buffer.append("public final class ");
buffer.append(className);
buffer.append(" implements ");
buffer.append(interfaceString);
buffer.append(" {"+ENTER);
//CLInvocationHandler成员变量
buffer.append("private CLInvocationHandler handler;"+ENTER);
//构造函数
buffer.append("public "+className+"(CLInvocationHandler handler) {"+ENTER);
buffer.append(" this.handler= handler;"+ENTER);
buffer.append("}"+ENTER);
for (int i =0 ;i < length;++i){
Class<?> clazz= interfaces[i];
Method[] methods = clazz.getMethods();
for (Method method : methods){
String returnTypeString = method.getReturnType().getName();
Class<?>[] parameterTypes = method.getParameterTypes();
StringBuffer paramTypeString = new StringBuffer();
StringBuffer methodParamString = new StringBuffer();
StringBuffer invokeParamString = new StringBuffer();
paramTypeString.append("new Class[]{");
int paramLength= parameterTypes.length;
//拼接参数
for (int j =0 ; j<paramLength ;++j){
Class<?> paramClazz= parameterTypes[j];
paramTypeString.append(paramClazz.getName()+".class");
String paramFieldName = "var"+j;
methodParamString.append(paramClazz.getName() +" "+paramFieldName);
invokeParamString.append(paramFieldName);
if (j!= paramLength-1){
paramTypeString.append(",");
methodParamString.append(",");
invokeParamString.append(",");
}
}
paramTypeString.append("}");
//修饰符
int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers)){
buffer.append("public");
}else if (Modifier.isPrivate(modifiers)){
buffer.append("private");
}else if (Modifier.isProtected(modifiers)){
buffer.append("protected");
}
buffer.append(" final "+returnTypeString+" "+ method.getName()+"("+methodParamString+"){"+ ENTER);
buffer.append("try{"+ENTER);
buffer.append("Method method = "+clazz.getName()+".class.getMethod(\""+method.getName()+"\","+paramTypeString+" );"+ENTER);
if (!"void".equals(returnTypeString)){
buffer.append("return ("+returnTypeString+")");
}
if (invokeParamString.toString().length()==0){
invokeParamString.append("null");
}else{
invokeParamString = new StringBuffer("new Object[]{"+invokeParamString.toString()+"}");
}
buffer.append("this.handler.invoke(this,method,"+invokeParamString+");"+ENTER);
buffer.append("}catch(Throwable e){"+ENTER);
buffer.append("e.printStackTrace();"+ENTER);
buffer.append("}"+ENTER);
if (!"void".equals(returnTypeString)){
buffer.append("return null;"+ENTER);
}
buffer.append("}"+ENTER);
}
}
buffer.append("}");
return buffer.toString();
}
//InvocationHandler实现
static class MyCLInvocationHandler implements CLInvocationHandler{
private Object source;
public MyCLInvocationHandler(Object source) {
this.source = source;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强
System.out.println("before");
Object result= method.invoke(source, args);
System.out.println("after");
return result;
}
}
//测试方法
public static void main(String[] args) throws Exception {
Person person = (Person)CLProxy.newProxyInstance(
new CLClassLoader(),
Donny.class.getInterfaces(),
new MyCLInvocationHandler(new Donny()));
String donny = person.call("donny");
System.out.println(donny);
person.eat();
}
}
//ClassLoader工具类
public class CLClassLoader extends ClassLoader {
private File classPathFile;
public CLClassLoader(){
String classPath = CLClassLoader.class.getResource("").getPath();
this.classPathFile= new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = CLClassLoader.class.getPackage().getName()+"."+name;
if (classPathFile!= null ){
File classFile = new File(classPathFile, name.replace("\\.", "/") + ".class");
if (classFile.exists()){
FileInputStream inputStream =null;
ByteArrayOutputStream outputStream = null;
try{
inputStream=new FileInputStream(classFile);
outputStream= new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len=inputStream.read(bytes))!=-1){
outputStream.write(bytes,0,len);
}
return defineClass(className,outputStream.toByteArray(),0,outputStream.size());
}catch (Exception e){
e.printStackTrace();
}finally {
if (inputStream!= null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return super.findClass(name);
}
}
这样应该就很清楚JDK是怎么实现动态代理的,为了后边Spring学习打基础,每天进步一点点 。