define
Provide a proxy for other objects to control access to this object
In some cases, an object is inappropriate or cannot directly reference another object, and a proxy object can act as an intermediary between a client and a target object
role
Without changing the code of the original class, but enhancing the functionality of the original class object can be added by selecting pre, post, surround, and exception handling
intentions
Provide a proxy for other objects to control access to that object
Main problem solving
Problems with accessing objects directly, such as objects that are accessed on remote machines. In object-oriented systems, some object for some reason (such as the object creation overhead is very large, or some operations require safety control, or need to access) outside the process, will have direct access to caused a lot of trouble for the user or the system structure, during a visit to this object we can add an object to this access layer
The advantages and disadvantages
Advantages:
- Clear responsibilities
- High expansibility
Disadvantages:
- Some types of proxy patterns can slow down the processing of requests due to the addition of proxy objects between the client and the real subject
- Implementing the proxy pattern requires additional work, and some of the proxy pattern implementations are quite complex
Differences from decorator patterns
The purpose of the proxy mode is to control the user’s access to the target object in the proxy and to enhance the function. The purpose of the decorator mode is to enhance the function on the basis of the original function
structure
Roles involved:
- Abstract Subject roles: Declare a common interface for real and proxy topics, so that proxy topics can be used wherever real topics can be used
- ProxySubject roles: ProxySubject roles contain internal references to real subjects, allowing them to manipulate real subject objects at any time. ProxySubject roles provide the same interface as real subject roles, allowing them to replace real subjects at any time. Controlling references to real topics and being responsible for creating or deleting real topic objects as needed, the proxy role usually performs an action before or after passing a client call to a real topic, rather than simply passing the call to a real topic object
- RealSubject roles: defines the real objects represented by proxy roles
The source code is as follows:
public abstract class Subject {
/** Declare an abstract request method */
abstract public void request(a);
}
Copy the code
public class RealSubject extends Subject {
/** constructor */
public RealSubject(a) {}/** The method to implement the request */
@Override
public void request(a) {
System.out.println("RealSubject implements request"); }}Copy the code
public class ProxySubject extends Subject {
private RealSubject realSubject;
/** constructor */
public ProxySubject(a) {}/** The method to implement the request */
@Override
public void request(a) {
preRequest();
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
/** The operation before the request */
private void preRequest(a) {
System.out.println("Pre-request action...");
}
/** The requested operation */
private void postRequest(a) {
System.out.println("Requested action..."); }}Copy the code
public class Client {
public static void main(String[] args) {
Subject subject = newProxySubject(); subject.request(); }}Copy the code
Look at the implementation from Teacher Tony
Static agent
The source code of the proxy class is created by the programmer or automatically generated by a specific tool, and then compiled. The.class file for the proxy class exists before the program runs
public class TuHao {
private double length;
public TuHao(double length) {
this.length = length;
}
public double getLength(a) {
return length;
}
public void setLength(double length) {
this.length = length;
}
public void dating(Girl girl) { girl.dating(length); }}Copy the code
public interface Girl {
/ * * * / date
boolean dating(double length);
}
Copy the code
public class TeacherCang implements Girl {
@Override
public boolean dating(double length) {
if (length >= 1.7 d) {
System.out.println("Height can, make an appointment!");
return true;
}
System.out.println("Height no line, brother we don't about!");
return false; }}Copy the code
public class Tony implements Girl {
private Girl girl;
public Girl getGirl(a) {
return girl;
}
public void setGirl(Girl girl) {
this.girl = girl;
}
@Override
public boolean dating(double length) {
doSomethingBefore();
boolean result = this.girl.dating(length);
doSomethingAfter();
return result;
}
/** * pre-enhanced */
private void doSomethingBefore(a) {
System.out.println("Boss, I tried this one, it's very good, I recommend it to you!");
}
/** post-enhanced */
private void doSomethingAfter(a) {
System.out.println("Boss, how do you feel, welcome to meet again next time!"); }}Copy the code
public class Client {
public static void main(String[] args) {
TuHao tuHao = new TuHao(1.8 d);
Girl girl = new TeacherCang();
Tony tony = newTony(); tony.setGirl(girl); tuHao.dating(tony); }}Copy the code
Disadvantages of static proxies:
- Poor scalability
- Scale-out: Proxy more classes
- Vertical scaling: Add more methods
- Poor maintainability
A dynamic proxy
Proxy classes are created dynamically when the program is running using reflection to create static proxies that know what to delegate beforehand, whereas dynamic proxies don’t know what to delegate until runtime
Advantages: Dynamically create proxies for different classes of objects at run time, enhance functions, flexible expansion, easy maintenance
There are two implementations:
- JDK dynamic Proxies: You can create proxies only for interfaces
- CGLIB dynamic proxy: You can create proxies for interfaces and classes
JDK dynamic proxy implementation
public class TonyCompany {
public static Object proxy(Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MyInvationHandler(target));
}
/** Functionality added to the implementation */
private static class MyInvationHandler implements InvocationHandler {
private Object target;
public MyInvationHandler(Object target) {
super(a);this.target = target;
}
public Object getTarget(a) {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doSomethingBefore();
/** Calls the proxied object's method */
Object result = method.invoke(target, args);
doSomethingAfter();
return result;
}
/** * pre-enhanced */
private void doSomethingBefore(a) {
System.out.println("Boss, I tried this one, it's very good, I recommend it to you!");
}
/** post-enhanced */
private void doSomethingAfter(a) {
System.out.println("Boss, how do you feel, welcome to meet again next time!"); }}}Copy the code
public class Client {
public static void main(String[] args) {
TuHao th = new TuHao(1.8 F);
Girl tc = newTeacherCang(); Girl girl = (Girl) TonyCompany.proxy(tc); th.dating(girl); }}Copy the code
A utility class can be used to view the.class file generated after the dynamic proxy:
public class ProxyUtils {
/* * Saves binary bytecode dynamically generated based on class information to disk, default is clazz directory params :clazz needs to generate dynamic proxy class * proxyName: for the name of the dynamically generated proxy class */
public static void generateClassFile(Class
clazz, String proxyName) {
// Generate bytecode based on the class information and the provided proxy class name
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName,
new Class[] { clazz });
ProxyUtils.writeToFile(clazz, classFile, proxyName);
}
public static void writeToFile(Class<? > clazz,byte[] classFile,
String proxyName) {
String paths = clazz.getResource(".").getPath();
System.out.println(paths);
FileOutputStream out = null;
try {
// Save to hard disk
out = new FileOutputStream(paths + proxyName + ".class");
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch(IOException e) { e.printStackTrace(); }}}}Copy the code
public interface Boy {
/ * * * / date
boolean dating(char cup);
/ * * * / taking pictures
void show(a);
}
Copy the code
public class TeacherChen implements Boy {
@Override
public boolean dating(char cup) {
if (cup == 'E') {
System.out.println("She's a nice girl to date!");
return true;
}
System.out.println("Not this girl, we don't date this girl!");
return false;
}
@Override
public void show(a) {
System.out.println("Go into photo mode..."); }}Copy the code
public class Client {
public static void main(String[] args) {
Boy boy = new TeacherChen();
Boy boy1 = (Boy) TonyCompany.proxy(boy);
boy1.dating('E'); boy1.show(); ProxyUtils.generateClassFile(Boy.class, boy1.getClass().getName()); }}Copy the code
You can see the files generated in the project:Click on the file identified above to generate a dynamically generated.class file:
public final class $Proxy0 extends Proxy implements Boy {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw newUndeclaredThrowableException(var4); }}public final void show(a) throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw newUndeclaredThrowableException(var3); }}public final String toString(a) throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw newUndeclaredThrowableException(var3); }}public final boolean dating(char var1) throws {
try {
return (Boolean)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw newUndeclaredThrowableException(var4); }}public final int hashCode(a) throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw newUndeclaredThrowableException(var3); }}static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.example.demo.syms.proxy.p2.Boy").getMethod("show");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.demo.syms.proxy.p2.Boy").getMethod("dating", Character.TYPE);
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw newNoClassDefFoundError(var3.getMessage()); }}}Copy the code
Implementation of cGLIb dynamic proxy
Cglib is a high-level Java bytecode generation and transformation API libraryMain purpose: generate dynamic proxy objects for classes and interfaces during runtime to achieve functional enhancement without changing the original code
Where is it commonly used: AOP, Test, ORM frameworks for generating dynamic proxy objects, intercepting property accessCode examples:
public class CglibDemo {
static class MyMethodInterceptor implements MethodInterceptor {
private Object target;
public MyMethodInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("* * * * * * * * *" + method.getName());
// Pre-enhanced
doSomethingBefore();
/ / the return value
Object result = null;
// Call this method of the parent class. It cannot be called when it is the proxy generating the interface.
//result = methodProxy.invokeSuper(o, objects);
if(target ! =null) {
// Call the proxied object's method with method
result = method.invoke(target, objects);
}
// post-enhance
doSomethingAfter();
return result;
}
private void doSomethingBefore(a) {
System.out.println("Hello boss, this I have tried, very good, recommend to you!");
}
private void doSomethingAfter(a) {
System.out.println("What do you think, boss? Welcome next time....."); }}public static void main(String[] args) {
// Cglib's enhancer, that is, agent
Enhancer e = new Enhancer();
// The proxied object
TeacherCang c = new TeacherCang();
// Set the agent to add action - callback
e.setCallback(new MyMethodInterceptor(c));
/** Interface proxy */
// Get the interface proxy object
e.setInterfaces(new Class[]{Girl.class});
Girl g = (Girl) e.create();
g.dating(1.8 D);
System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
/** class proxy */
// Generate a proxy object for the class
e.setSuperclass(TeacherCang.class);
e.setInterfaces(null);
TeacherCang tc = (TeacherCang) e.create();
tc.dating(1.8 D);
// When there are multiple callbacks, callbackFilter is used to specify the number of callbacks to be used by the propped method
//e.setCallbacks(new Callback[] {new MyMethodInterceptor(tc), new YouMethodInterceptor(tc)});
/* e.setCallBackfilter (new CallbackFilter() {@override public int accept(Method) { If ("dating". Equals (method.getName())) {return 1; } return 0; }}); * /}}Copy the code