Before we learn about agent, let’s first understand the meaning of agent
- Definition: A proxy object is provided to the target object, and the proxy object controls the reference to the target object
- Purpose: To indirectly access the target object by introducing proxy, and to prevent the uncertain complexity brought to the system by directly accessing the target object
Why are there agents?
In traditional object-oriented thinking, if you want to achieve functional reuse, either inheritance or reference, either way, the code has a certain degree of intrusion, coupling is inevitable
Invasive meaning:
If you want to use it to enhance your program, you have to change your program code, and it’s invasive! It’s fine if only one or two features need to be enhanced, but if there are a lot of feature points that need to be enhanced, it’s a lot of work and the code isn’t elegant! Imagine if you exposed a set of interfaces to the public, and all of a sudden the leader said, interfaces need permission control. Where to add? The dumbest thing to do, of course, is to write a program that validates the logic and then calls every interface. This is also the short board of object-oriented thinking, in order to add some general functions for the program, can only be carried out through coupling. Proxy (dynamic proxy) can solve this problem!
Static versus dynamic proxies
Agents can be divided into static agents and dynamic agents according to the loading time of the proxied class.
- Static proxy: The proxied class is determined at compile time
- Dynamic proxy: The runtime determines which class is being proxied
Static proxy usage
1, static proxy to achieve the method
public interface Subject {
void sayGoodBye(a);
void sayHello(String str);
boolean isProxy(a);
}
Copy the code
2, define the proxy class (original function class) and implement the proxy class function logic (dead do not change the kind of)
public class RealSubject implements Subject {
@Override
public void sayGoodBye(a) {
System.out.println("RealSubject I'm the same code sayGoodBye");
}
@Override
public void sayHello(String str) {
System.out.println("RealSubject I'm the same code sayHello" + str);
}
@Override
public boolean isProxy(a) {
System.out.println("RealSubject, I'm the same code isProxy.");
return false; }}Copy the code
3. Define a static proxy class (function addition class). This proxy class must also implement the same Subject interface as the proxy class, so as to facilitate the enhancement of the original function
public class ProxySubject implements Subject {
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void sayGoodBye(a) {
SayGoodBye can do things before calling sayGoodBye (such as whether permission authentication can be called)
System.out.println("ProxySubject sayGoodBye begin " +
"Proxy class, enhanced functionality that sayGoodBye can do before calling (such as whether permission authentication can be called)");
// Indirectly access the proxied object's methods in the methods of the proxy class
subject.sayGoodBye();
System.out.println("ProxySubject sayGoodBye end " +
"Here you can handle the logic after the original method call.");
}
@Override
public void sayHello(String str) {
SayHello can do operations (such as whether permission authentication can be invoked) and test methods with arguments before calling sayHello
System.out.println("ProxySubject sayHello begin " +
"Proxy class, enhanced functionality that sayHello can do before calling (such as whether permission authentication can be called)");
// Indirectly access the proxied object's methods in the methods of the proxy class
subject.sayHello(str);
System.out.println("ProxySubject sayHello end " +
"Here you can handle the logic after the original method call.");
}
@Override
public boolean isProxy(a) {
IsProxy can perform operations (such as whether permission authentication can be called) and test methods with returns before calling isProxy
System.out.println("ProxySubject isProxy begin " +
"Proxy class, enhanced functionality isProxy can do operations before calling (such as whether permission authentication can be called)");
boolean boolReturn = subject.isProxy();
System.out.println("ProxySubject isProxy end " +
"Here you can handle the logic after the original method call.");
returnboolReturn; }}Copy the code
4, static proxy use
public class ProxyMain {
public static void main(String[] args) {
In some cases, we don't want to modify existing code. We use proxies to access objects indirectly
RealSubject realSubject = new RealSubject();
// Proxy objects, pass in objects that the original code does not want to modify
ProxySubject proxySubject = new ProxySubject(realSubject);
// Call the method of the proxy class object
proxySubject.sayGoodBye();
System.out.println("* * * * * *");
proxySubject.sayHello("Test");
System.out.println("* * * * * *"); proxySubject.isProxy(); }}Copy the code
5. Final print
ProxySubject sayGoodBye Begin proxy class, SayGoodBye ProxySubject sayGoodBye End sayGoodBye ProxySubject sayGoodBye End sayGoodBye ProxySubject sayGoodBye End ****** ProxySubject sayHello begin Proxy class, SayHello Test ProxySubject sayHello End sayHello Test ProxySubject sayHello End sayHello Test ProxySubject sayHello End sayHello ****** ProxySubject isProxy begin Proxy class, RealSubject isProxy ProxySubject isProxy End here can handle the logic processing after the original method is calledCopy the code
6. Conclusion:
Static proxy (traditional proxy mode) implementation is more violent and direct, need to write all the proxy classes of all methods, and one by one to manually forward the past, troublesome and tedious. So we are going to learn and use dynamic proxies.
Core principles of dynamic proxy
There are two important classes or interfaces in Java’s dynamic proxy mechanism
- One is that the InvocationHandler(Interface) needs to implement that Interface in your code
- One is Proxy(Class)
2. InvocationHandler (Interface
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
Copy the code
- Proxy: indicates the generated proxy object.
- Method: Refers to a method object of the real object we want to call;
- Args: refers to arguments accepted when a method of the real object is called;
- Return value Object: the method called by the proxy needs to be returned intact
3. Core principle of Proxy (Class)
- When compiled, the class of the Proxy object does not exist. When the proxy. newProxyInstance method is called, a class bytecode of Proxy0 is constructed and loaded into memory
4, Proxy. NewProxyInstance method details
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader, Class
[] interfaces, InvocationHandler h)
throws IllegalArgumentException
{....}
Copy the code
- Loader: A ClassLoader object that defines which ClassLoader object loads the generated proxy object
- Interfaces: an array of Interface objects that represent the set of interfaces I am going to provide to the object THAT I want to delegate. If I provide interfaces to it, the proxy object claims to implement that Interface (polymorphic) so that I can call methods in that set of interfaces
- An InvocationHandler object that represents which InvocationHandler object the dynamic proxy object is associated with when calling a method.
Dynamic proxy usage
Step 1: Define an interface (logic to be implemented)
public interface Subject {
void sayGoodBye(a);
void sayHello(String str);
boolean isProxy(a);
}
Copy the code
Step 2: Define the real object (proxy class, never change) :
public class RealSubject implements Subject {
@Override
public void sayGoodBye(a) {
System.out.println("RealSubject I'm the same code sayGoodBye");
}
@Override
public void sayHello(String str) {
System.out.println("RealSubject I'm the same code sayHello" + str);
}
@Override
public boolean isProxy(a) {
System.out.println("RealSubject, I'm the same code isProxy.");
return false; }}Copy the code
Step 3: Define an InvocationHandler, which is equivalent to a proxy handler
public class SubjectInvocationHandler implements InvocationHandler {
// This is the real object we want to delegate
private Object subject;
Constructor that assigns an initial value to the real object we want to proxy
public SubjectInvocationHandler(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
// We can add our own operations before propping up the real object
System.out.println("Before Method invoke proxy class, function enhanced before calling"+method+"Actionable actions (such as whether permission authentication can be invoked)");
System.out.println("Method:" + method);
// When a proxy object calls a method of the real object, it automatically jumps to the invoke method of the handler object associated with the proxy object to invoke the corresponding return value, and finally returns the corresponding return value
Object obj = method.invoke(subject, args);
// We can also add some operations of our own after the real object is propped up
System.out.println("After Method invoke here can handle the logic after the original Method call");
returnobj; }}Copy the code
Step 4: Invoke
public class ProxyMain {
public static void main(String[] args) {
// Proxy class
Subject realSubject = new RealSubject();
// We pass the object to the class we want to proide, and finally call its methods through the proided object
SubjectInvocationHandler handler = new SubjectInvocationHandler(realSubject);
// Generate the proxy class
Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(), handler);
// Outputs proxy objects
System.out.println("Proxy : " + subject.getClass().getName());
System.out.println("Proxy super : " + subject.getClass().getSuperclass().getName());
System.out.println("Proxy interfaces : " + subject.getClass().getInterfaces()[0].getName());
Call the sayGoodBye method of the proxy class
subject.sayGoodBye();
System.out.println("-- -- -- -- -- -- -- --");
Call the sayHello method of the proxy class
subject.sayHello("Test");
System.out.println("-- -- -- -- -- -- -- --");
System.out.println("---subject.isProxy()-----"+ subject.isProxy()); }}Copy the code
Final print:
Proxy : com.sun.proxy.$Proxy0
Proxy super: java.lang.reflect.proxy Proxy interfaces: StaticProxy.Subject before Method invoke Proxy classes that enhance functionality before invokingpublic abstract voidStaticproxy. Subject. SayGoodBye () to do operation (such as whether to call the permissions authentication) Method:public abstract voidStaticproxy. Subject. SayGoodBye () RealSubject I sayGoodBye is intact code after Method invoke here can deal with the original Method call logic to handle after the -- -- -- -- -- -- -- -- before Method Invoke proxy class, function enhancement before callingpublic abstract voidStaticproxy. Subject. SayHello (Java. Lang. String) can do operations (such as whether it can call the access authentication) Method:public abstract voidStaticproxy. Subject. SayHello (Java. Lang. String) RealSubject I am intact code sayHello Test after Method can invoke this logic to handle after dealing with the original Method call -------- before Method invoke proxy class, function enhanced before callingpublic abstract booleanStaticproxy. Subject. IsProxy () to do operation (such as whether to call the permissions authentication) Method:public abstract booleanRealSubject staticproxy. Subject. IsProxy () I was intact code isProxy after Method can invoke this logic to handle after dealing with the original Method call ---subject.isProxy()-----false
---subject.isProxy()-----false
Copy the code
Dynamic proxy summary
- Dynamic proxies can add flexibility to programs, such as logical processing before and after method calls
- Perfect for decoupling, dynamic proxies can separate the invocation layer from the implementation layer
- Dynamic proxies do not require interface implementation classes
- Dynamic proxies can address the flow of program execution (moving events to activities in the next section)