The Java standard library has a java.lang.reflect.Proxy
class. .. This class was added from J2SE 1.3, and the provided function is generally called Dynamic Proxy (hereinafter referred to as "** Dynamic Proxy **" in Japanese). Since J2SE 1.3 was released in May 2000, dynamic proxies have been around for a long time and are already dead technology, but they are still used by many Java frameworks and libraries. On the other hand, it seems that the general Java programmers are not very well known.
In this article, for those who understand the basic Java grammar, we will introduce common proxy patterns to understand dynamic proxies, explain the need for dynamic proxies, and then explain the need for dynamic proxies. Explains how to use Java's dynamic proxy. It also shows how to implement dynamic proxies for languages other than Java (C #, Python, EcmaScript).
The Java code posted in this article has been confirmed to work in the following environment. (The operating environment of languages other than Java will be described at any time.) Also, the Java code posted omits some import clauses required for compilation.
name | version |
---|---|
OpenJDK | 11.0.1 |
Understanding how to use the dynamic proxy java.lang.reflect.Proxy
shouldn't be difficult for programmers who are familiar with Java. However, in order to understand the need for dynamic proxies and use them effectively, understand the " static </ b>" proxy, which is the opposite of " dynamic </ b>". need to do it. This was explained in "I will explain the Proxy Pattern as easily as possible".
In "I will explain the Proxy Pattern as easily as possible", ** One about multiple classes that represent a common interface. Introduced up to ** points where common processing can be defined with the proxy of. In this article, we'll start with that anti-pattern.
There are anti-patterns in applying static proxies.
Here is a more specific example of the "proxy that adds common processing for multiple concrete classes to an interface" shown above.
An implementation of the model layer of a sales site defines three classes: "** customer ", " order ", and " product **". In order for this class to access the RDBMS in the processing of all methods, it is necessary to get an RDBMS connection and start a transaction before executing the method. Then, after execution, it is necessary to commit or roll back the transaction and close the connection.
All three classes are "** add " to create data, " update " to update data, and " search" to search data. It seemed that it would be enough if there was a method of "" and " get details **" to get detailed data. Therefore, these three classes are concrete classes of the interface called
Model
. Then, define a class calledTransactionBarrier
, which is a proxy for RDBMS processing, with a concrete class ofModel
.
It is a class diagram showing the relationship between these classes.
To some extent, the class design above worked well, but one day I run into problems.
"Customer" information needs to be deleted in bulk to protect customer information.
Therefore, a method called "** Bulk Delete *" is added to "Customers", but this "Batch Delete" method also requires pre-post processing of RDBMS by
TransactionBarrier
. Therefore, add a method called " Delete all *" to theModel
interface as well.Then, you will have to add the "* Bulk Delete *" added to the
Model
interface to the" Orders "and" Products "that do not require the" * Bulk Delete * "method. However, in reality, "Order" and "Product" do not want to call "Delete all", so add the@deprecated
tag to the" Delete all "method for" Order "and" Product ". I had to throw ʻUnsupportedOperationException` unconditionally when this method was called in.
In the above example, it is difficult to convey the seriousness of the situation because only one special method addition occurred in three classes, but in actual system development, dozens to hundreds of models are defined depending on the project. .. Then, every time you define your own method in each model, the above cases occur frequently, and a lot of methods that throw ʻUnsuppportedOperationException` will be added to each class.
The reason for falling into this situation is that * a group of classes that should not be implemented as one interface is forcibly derived from one interface because we want to implement common processing with a proxy *.
Originally, "** Customer ", " Order ", and " Product **" should have defined separate interfaces and proxies, as shown below.
However, in the above class design, the proxy class must be implemented for each interface, which is very troublesome. In the first place, even though there is a one-to-one relationship between the interface and the class as described above, if you define a proxy that implements the same processing for each, even if you implement the common processing directly in the implementation class, it will take time to implement. Even the benefits of using a proxy are lost in that it doesn't change.
It would be nice if there was a proxy that could be defined by one implementation even for multiple different interfaces, but such an implementation is not possible with the normal Java syntax. However, dynamic proxies allow you to ** implement a common proxy across multiple interfaces **.
Now, let's introduce an implementation example using the dynamic proxy java.lang.reflect.Proxy
(hereinafter referred to as" ** Proxy
**"). </ p>
First, define the class mediated by Proxy
and its interface. This code is for MyInterface
and MyClass
posted in "I will explain the Proxy Pattern as easily as possible". Same as implementation.
MyInterface.java
public interface MyInterface {
public String myMethod(String value);
}
MyClass.java
public class MyClass implements MyInterface {
@Override
public String myMethod(String value) {
System.out.println("Method:" + value);
return "Result";
}
}
To use Proxy
, you must define a concrete class for the java.lang.reflect.InvocationHandler
interface. The concrete class of ʻInvocationHandler implements the ʻinvoke (Object, Method, Object [])
method. This ʻinvoke` method is a method that implements specific proxy processing.
ʻThe code of MyInvocationHandler
in the implementation example of the concrete class of InvocationHandler. In the proxy processing of
MyInvocationHandler,
MyInvocationHandler: startis output as pre-processing and
MyInvocationHandler: exit` is output as standard output in post-processing.
MyInvocationHandler.java
import java.lang.reflect.*;
/** java.lang.reflect.InvocationHandler implementation class that implements proxy processing specified in Proxy*/
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DynamicProxy:before");
Object result = method.invoke(target, args);
System.out.println("DynamicProxy:before");
return result;
}
}
To use the MyInvocationHandler
defined above, use the newProxyInstance
method of the Proxy
to get the object of the Proxy
.
Specify the object of the MyInvocationHandler
class defined above in the third argument of the newProxyInstance
method.
MyClass myClassObj = new MyClass();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(myClassObj);
MyInterface proxiedObj = (MyInterface)Proxy.newProxyInstance(MyClass.class.getClassLoader(),
new Class[] { MyInterface.class },
myInvocationHandler);
System.out.println(proxiedObj.myMethod("Argument"));
This is the result of executing the above code.
Execution result
DynamicProxy:before
Method:Argument
DynamicProxy:after
Result
First, I will explain the newProxyInstance
method of Proxy
.
You can get a Proxy
object with newProxyInstance
. The user casts the acquired ʻObject type object to one of the types in the class array of the interface specified by the second argument and uses it. The return value of this method is of type ʻObject
, but it is a derived class of the Proxy
class and is a concrete class of all interfaces of the second argument.
MyInterface proxiedObj = (MyInterface)Proxy.newProxyInstance(MyClass.class.getClassLoader(),
new Class[] { MyInterface.class },
myInvocationHandler);
newProxyInstance
. Since the class loader can be obtained from all classes with the getClassLoader ()
method, it can be obtained with the getClassLoader ()
of any class, but an environment using many class loader chains such as Web applications. It is better to specify the class that is implemented independently in the application as much as possible, assuming that it will be used in.
Here, the class loader of MyClass, which is a class mediated by a dynamic proxy, is specified.newProxyInstance
.
In Java, one class can implement multiple interfaces, so specify it as an array so that you can generate a dynamic proxy that implements multiple interfaces.newProxyInstance
, specify an object of the concrete class of ʻInvocationHandler. The object specified by this argument is the process that is actually executed inside the dynamic proxy. Here, we actually implemented
MyInvocationHandler, which is a concrete class of ʻInvocationHandler
, so that object is specified.Next, I will explain the ʻinvoke method of the ʻInvocationHandler
interface implemented in MyInvocationHandler
.
ʻImplement proxy processing with the invokemethod. Whenever a method that embodies the interface of a
Proxy object is called, it calls this ʻinvoke
method. ʻInvoke method is passed as an argument which method of the
Proxy` object was called with what argument.
** If you want to implement a general proxy **, call the method of the target object in the ʻinvoke method. The method to call is passed as an argument to the ʻinvoke
method, but the object to call is held by the concrete class of ʻInvocationHandler` itself.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
is passed to the ** first argument ** of ʻinvoke
. is passed an object of the
Methodclass that represents the method called by the
Proxy object. In the process of ʻinvoke
, the method of the actual object is called using the value of this argument., the argument specified in the method in which the
Proxy` object is called is passed as an Object array.
This also uses the value of this argument to call the method of the actual object.If you look at the result of executing the implementation of the dynamic proxy, you can get the same execution result as "2-2. Defining the proxy class", so it is easy to understand that the dynamic proxy is working as a proxy. I will. But why call this "** dynamic **"?
To understand the "dynamic" nature of a dynamic proxy, run the code that calls the newPorxyInstance
of the Proxy
as follows: You can leave the MyInvocationHandler
in the implementation shown above.
ArrayList<String> list = new ArrayList<String>();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(list);
@SuppressWarnings("unchecked")
List<String> proxiedObj = (List<String>)Proxy.newProxyInstance(MyInterface.class.getClassLoader(),
new Class[] { List.class },
myInvocationHandler);
proxiedObj.add("hoge");
This is the result of executing the above code.
Execution result
DynamicProxy:before
DynamicProxy:after
The output of the above execution result shows that the call to proxiedObj.add ("hoge");
called ʻinvoke of
MyInvocationHandler`.
It should be noted here that what used to be able to get the Proxy
object of MyInterface
can also get the proxy of the List
interface without changing the MyInvocationHandler
at all. The code for MyInvocationHandler
has no MyInterface
or List
characters, and MyInvocationHandler
does not actually depend on these interfaces at all. By specifying the interface class of the second argument of newProxyInstance
of Proxy
, a new class is generated ** during execution of newProxyInstance
** inside Proxy
, and the Proxy
object is acquired. I will.
The relationship between the dynamic proxy and the implemented class is shown in the class diagram.
The green class is a class prepared before the Java process is started, while the red class is created after the Java process is started and the newProxyInstance
of Proxy
is called ** (instance). Not) class **. newProxyInstance
returns an instance of the newly created class (although it will be retrieved from the map if it has already created the same class).
** How, the process in the newProxyInstance
method creates a class that doesn't exist in the source code! ** [^ 1]
Proxy "** static " and " dynamic " are pre-defined and invariant proxy classes that are " static" during the period in which the Java process is running. "", the proxy class generated from the middle of the process being executed is called " dynamic **".
This is the end of how to use Proxy
.
However, in the dynamic proxy implementation examples introduced so far, the user of the object calls newProxyInstance
of Proxy
to get the Proxy
object including the target object. However, this implementation is not very convenient.
Therefore, there is a GoF design pattern called ** Factory Pattern **, so we will use this pattern to simplify the code to get the Proxy
object. The factory pattern is a method to obtain from the method of the dedicated class that creates the object without calling the constructor directly to the user when creating the object.
For example
Factory pattern example ①
MyInterface myObj = MyFactory.getInstance();
If the Proxy
object can be obtained by calling thegetInstance ()
method of MyFactory
, the implementation on the Proxy
object user side will be very simple.
However, since the getInstance ()
method of MyFactory
does not pass any information from the caller, as it is, it always goes through the same ʻInvocationHandler and the same class (here,
Proxy that calls the object of MyClass
". You can only get objects. If you pass the
MyInterfaceclass, the
MyClass object and the ʻInvocationHandler
object as arguments, it will be a versatile factory. But if you think about it, the ʻInvocationHandler is a proxy. Since it is the definition of the processing to be executed, the factory may use a fixed concrete class of ʻInvocationHandler
internally (switching the concrete class of ʻInvocationHandleris possible by separating the factory class and the method). Also, if the derived class for the
MyClass object is fixed at
MyClass`, it is not necessary to specify it as an argument.
Therefore, here, we will implement a factory that acquires the Proxy
object by specifying only the interface in the argument of the factory as shown below.
Factory pattern example ②
MyInterface myObj = MyFactory.getInstance(MyInterface.class);
Assuming you implement a factory like the one above, there is one problem.
Since only the interface class is specified in this argument, it is necessary to get the derived class for the interface inside the factory and create an object of that derived class. The easiest way to do this is to have a map of the classes for the interface in the factory. This method is fine and practical enough, but in a system where there are dozens or hundreds of interface and class definitions, each time a new interface and class is defined, it is in the factory. You need to add a map, which is a bit annoying and can cause source conflicts in group development.
Therefore, here we will introduce how to specify the derived class in the additional information of the interface. First, define the annotation as follows.
MyAnnotation.java
/**Annotation that specifies the implementation class for the interface*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
Class<?> concretizedClass();
}
Add this annotation to the MyInterface
you defined earlier.
In the annotation argument, specify the derived class to select in the factory.
MyInterface.java
/**Added implementation class definition to instantiate with annotation*/
@MyAnnotation(concretizedClass = MyClass.class)
public interface MyInterface {
public String myMethod(String value);
}
Finally, it is an implementation of MyFactory
which is a factory class. The concrete class of ʻInvocationHandler is defined by the anonymous class in the
getInstancemethod of
MyFactory`.
MyFactory.java
/**Class that creates an object of the interface specified by the argument*/
public class MyFactory {
/**Method to get the object of the implementation class of the interface specified by the argument interfaceClass*/
public static <I> I getInstance(Class<I> interfaceClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//Get the implementation class for MyInterface from the annotation of MyInterface
MyAnnotation myAnnotation = interfaceClass.getAnnotation(MyAnnotation.class);
Class<?> objClass = myAnnotation.concretizedClass();
//Create an implementation class object
@SuppressWarnings("unchecked")
I obj = (I)objClass.getDeclaredConstructor().newInstance();
//Create an object by defining InvocationHandler with an anonymous class
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DynamicProxy:before");
Object result = method.invoke(obj, args);
System.out.println("DynamicProxy:after");
return result;
}
};
//Create a proxy object
@SuppressWarnings("unchecked")
I proxiedObj = (I)Proxy.newProxyInstance(interfaceClass.getClassLoader(),
new Class[] { interfaceClass },
invocationHandler);
return proxiedObj;
}
}
It is the implementation and execution result of the above MyFactory
user side.
MyInterface myObj = MyFactory.getInstance(MyInterface.class);
System.out.println(myObj.myMethod("Argument"));
Execution result
DynamicProxy:before
Method:Argument
DynamicProxy:after
Result
With the above improvements, we're getting closer to the actual "usable" code, but there's still room for improvement and issues that need to be fixed.
They are listed below for your reference when actually applying a dynamic proxy.
getInstance
method of MyFactory
is throwing the NoSuchMethodException
that can occur internally. Exceptions that cannot actually occur should not be included in the throws clause specified by the argument, it should be checked that ʻobjClass
specified by the annotation is a concrete class of ʻinterface Class`. for ʻinterface Class
directly to MyFactory, or to set it from the configuration file, in addition to the interface annotation.as it is, or to throw the
Throwable object that caused it in
getCause () `.getInstance ()
creates a new Proxy
object every time, but if it is a good object with Sigletone, do not create it every timeProxy
to get objects by DI (Devedency Injection) instead of using MyFactory
directlyIn addition to the factory pattern, the pattern that determines the derived class for such an interface and returns an appropriate object is called the ** ServiceLocator pattern **.
So far, we have introduced dynamic proxies using Java. This chapter introduces how dynamic proxies are provided in other programming languages.
5-1.C#
(According to cfm-art, the standard RealProxy provides the dynamic proxy function. This chapter will be added again.)
The .NET Framework, the standard library for ~~ C #, does not have a class equivalent to a dynamic proxy. ~~ ~~ However, ~~ The Castle of the external project provides the dynamic proxy function in the external library.
name | version |
---|---|
.NET Framework | 4.6.1 |
Castle.DynamicProxy2 | 2.2.0 |
DynamicProxyTest.cs
using Castle.Core.Interceptor;
using Castle.DynamicProxy;
namespace MyNamespace
{
public interface IMyInterface
{
string MyMethod(int value);
}
public class MyClass : IMyInterface
{
public string MyMethod(int value)
{
Console.WriteLine("MyMethod:" + value);
return "Result";
}
}
public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("MyInterceptor:before");
object ret = invocation.Method.Invoke(invocation.InvocationTarget, invocation.Arguments);
Console.WriteLine("MyInterceptor:after");
invocation.ReturnValue = ret;
}
}
}
ProxyGenerator generator = new ProxyGenerator();
IMyInterface proxy = generator.CreateInterfaceProxyWithTargetInterface(
typeof(IMyInterface),
new MyClass(),
new MyInterceptor()) as IMyInterface;
Console.WriteLine(proxy.MyMethod(1));
Execution result
MyInterceptor:before
MyMethod:1
MyInterceptor:after
Result
As you can see by looking at the methods defined in ProxyGenerator
, there are many functions provided by Java Proxy
. In Java, the Proxy
class can only be created in a concrete class of an interface, but in C # ProxyGenerator
you can create a dynamic proxy for a class derived class in addition to the interface.
5-2.Python Python also has no equivalent to a dynamic proxy. However, standard special methods can be used to achieve dynamic proxy-equivalent functionality.
name | version |
---|---|
Python | 3.7.1 |
dynamicProxyTest.py
class MyProxy(object):
def __init__(self, obj):
self._obj = obj
def __getattr__(self, name):
def func(*args):
print(before)
result = getattr(self._obj, name)(*args)
print('after')
return result
return func
class MyClass(object):
def myFunction(self, arg):
print('myFunction ' + arg)
return 'result'
myObj = MyClass()
myProxy = MyProxy(myObj)
print(myProxy.myFunction('arg'))
Execution result
before
myFunction arg
after
result
This MyProxy
class is a brief explanation for those who are not familiar with Python grammar.
In Python, there is a special method (Special Method) of a method with a specific name with "\ _ \ _" before and after the class definition. Special methods are called by certain events that occur on an object, such as creating an object, calling an attribute, or being specified by the value of a particular operator.
The __getattr__
method is called when you try to get an Attribute that is not defined in an object of that class. The user side of the object gets the return value of __getattr__
as the attribute value if the attribute with the name specified in the class is not defined.
In Python, all variables and methods on a class are attributes. The MyProxy
class defines only two special methods, the __init __
method and the __ getattr__
method, so it tries to get attributes from an object of this class (that is, it tries to call some method). And the __getattr__
method is always called. Therefore, in order for MyProxy
to behave in the same way as a dynamic proxy, we define a function called func
inside the __getattr__
method that acts as a proxy and return that function.
The caller implementation is one line,
myProxy.myFunction('hoge')
However, this is different from Java method invocation.
myFunction
from the myProxy
object.('hoge')
.Should be interpreted as. I tried to get the attribute named myFunction
from the myProxy
object, but since myProxy
did not have the attribute named myFunction
, I get the return value from the __getattr__
method and execute it.
5-3.EcmaScript(JavaScript)
EcmaScript provides a class called Proxy
from 6 onwards. However, it is used differently from Java's Proxy
and acts as an event handler for the object.
Here, we will introduce a function called ʻapply, which is one of the event handlers in
Proxy. The ʻapply
function is an event handler that is called when you call the function.
name | version |
---|---|
node.js | v6.11.3 |
dynamicProxyTest.js
function myFunction(arg1, arg2) {
console.log("myFunction:" + arg1 + ", " + arg2);
return "result";
}
const handler = {
apply : function (target, thisArg, argumentsList) {
console.log("before");
var result = target(...argumentsList);
console.log("after");
return result;
}
}
let proxy = new Proxy(myFunction, handler);
console.log(proxy("hoge", "hage"));
Execution result
before
myFunction:hoge, hage
after
result
If you read this far, you should be able to implement it with a dynamic proxy. However, due to the high degree of freedom and the special features of dynamic proxies, even if they meet the functional requirements if misused, they are also technologies that may involve non-functional problems. The languages introduced in "5. Dynamic Proxy in Other Languages" are major programming languages that are widely used at the time of writing this article (December 2018), but ~~ are all standard libraries. It should be noted that it does not provide a dynamic proxy ~~. To put it the other way around, the use of dynamic proxies is itself an anti-pattern. [^ 2]
Here, the features of the dynamic proxy are summarized below.
Among these features, "2. Completely separate the processing of the dynamic proxy from the processing mediated by the proxy" is both an advantage and a disadvantage of the dynamic proxy. Developers of classes that implement objects mediated by dynamic proxies may not be aware of the fact that their classes are being called by dynamic proxy mediated in the environment in which the application actually runs. However, assuming that dynamic proxy mediation is essential for the class to work, inside the proxy in order to reuse the class you created in another environment or run it in your own environment for testing. The difficulty will increase because you have to reproduce the process of. It can also make it difficult to resolve errors and failures.
The simplest alternative to dynamic proxies is to use a lambda expression to define the proxy as follows:
MyInterface myObj = new MyClass();
MyProxy.invoke(() -> { nyObj.myMethod(); });
In the MyProxy
ʻinvoke method, you can implement the proxy processing and call the
Runnableobject passed as an argument to call the original processing that was mediated. This method also allows you to implement proxies across interfaces and classes. What's more, developers can see what kind of mediation the class they define is called by looking at the implementation of
MyProxy`.
Based on the above, I will give an example of use that seems to be an anti-pattern of the application method of dynamic proxy. However, these patterns are not necessarily patterns that should not be used. Is Dynamic Proxy Application Really Optimal? Are there any other more effective alternatives? It's an anti-pattern in the sense that you should consider. The original meaning of a proxy is an agent. Therefore, I will introduce anti-patterns under the title of "○○'s agent" below.
For example, in the process of checking the input value in the method for retrieving information in the class defined to handle limited information such as users in a huge Web system, it is dynamic. Applying a proxy may not be very desirable. Even if processing normalization and standardization are required due to the large number of input value items, there are other ways to standardize some of the large number of different processing other than dynamic proxy.
Dynamic proxies have the side effect of making it difficult to read the whole picture of the process from your code because it completely separates the process. Even if the scale of processing in a small area becomes large, it would be desirable to implement it so that the whole can be grasped.
Suppose that the contents of the concrete class of ʻInvocationHandler used by
Proxy` are not exposed, but the developer is forced to implement a class that can be executed only through the processing of the dynamic proxy. Keeping the prerequisites of the implementation you develop secret can be stressful for developers. Of course, if the system encounters problems caused by dynamic proxy processing, as well as psychological problems, the developer can spend a lot of time investigating them. Also, it may be difficult to reuse the implemented processing.
This is a case where the responsibility of the dynamic proxy becomes ambiguous. Initially, the dynamic proxy was implemented only for non-system operations such as log output and DB-related initialization / termination processing, but HTTP request body parsing processing is included and pre-check processing is performed. This is a case where the responsibility of the dynamic proxy increases as the approval process is entered.
This isn't just about dynamic proxies, but class responsibilities should be clarified. You should also follow that policy when making corrections. If necessary, you should go through multiple dynamic proxies with different responsibilities.
In the case where the system has a multi-layered structure such as the controller layer, service layer, logic layer, and data access layer, or in a system in which objects depend on each other in a complicated manner, all objects act as agents. In this situation, some proxies may be needed for processing, but you can imagine that many proxies are not needed. Proxy mediation should be limited to what you need, and you should carefully consider whether you really need other proxy mediation.
As many of you may have noticed by reading the implementation example of the concrete class of ʻInvocationHandler,
Proxy does not enforce the implementation of the proxy pattern. Whether or not to actually call the method passed as an argument in the ʻinvoke
method of ʻInvocationHandler is completely up to the implementer of the ʻInvocationHandler
concrete class. Therefore, Proxy
can be applied to other than proxy patterns.
For example, DTO (Data Transfer Object) is a pattern that defines class members and their corresponding set and get methods. This is because the DTO definition is only the interface that declares the set method and get method, and the internal implementation is defined by ʻInvocation Hadler`.
MyDtoInvocationHadler.java
public class MyDtoInvocationHandler implements InvocationHandler {
private Map<String, Object> map = new HashMap<String, Object>();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Processing of methods starting with get
if (method.getName().startsWith("get")) {
return map.get(method.getName().substring(3));
}
//Processing of methods starting with set
else if (method.getName().startsWith("set")) {
//abridgement
}
}
}
It is doubtful that this application is really useful. Even if you can omit the implementation of the DTO class, you need to define the interface, and you must define the set method and get method of each item in the interface. In most development projects, the implementation of the Entity class corresponding to the DTO class and DB table will have a tool that automatically outputs the code from the design document etc. instead of handwriting. In that case, it doesn't really matter whether the output code is a class or an interface. Conversely, it deprives developers of the option of incorporating implementations other than simple class member interactions into a particular DTO.
It's not a restaurant. An agent that requires a large amount of information in interface annotations and configuration files to mediate the agent. It often happens when you try to make Proxy
perform a process other than proxy, as in" 6-5. Proxy-like ". If a large amount of information is ordered from an agent user, shouldn't it be implemented independently by the user instead of the agent?
That concludes the explanation of dynamic proxies in this article. For more detailed explanation, please read the reference site below.
Understanding dynamic proxies is not difficult at all, but as I mentioned in "1. Introduction", in my personal experience, I feel that the general Java programmers of dynamic proxies are not very well known. I will. We speculate that this is due to the following reasons.
However, if you are a programmer who has worked on some Java development projects, when you run your code on the framework, the stack trace shows a class call that you don't recognize. Have you ever felt strange when you saw? To answer such questions, it's a good idea to understand dynamic proxies. Also, I don't think Java's dynamic proxy knowledge is wasted when learning other programming languages from Java.
On the other hand, while the release of J2SE 1.3 including Proxy
was in May 2000, it is irrelevant that Martin Fowler proposed POJO (Plane Old Java Object) in September 2000. However, I couldn't handle it in this article due to lack of preparation.
We hope that this article will give you an opportunity to gain knowledge of dynamic proxies.
https://docs.oracle.com/javase/jp/10/docs/api/java/lang/reflect/Proxy.html https://docs.oracle.com/javase/jp/8/docs/technotes/guides/reflection/proxy.html https://www.ibm.com/developerworks/jp/java/library/j-jtp08305/
[^ 1]: Strictly speaking, the official Java documentation shown on the reference site above says because the proxy class code is generated by trusted system code
, only in the newProxyInstnce
method Does not specify that it will generate a new class. It really depends on the VM implementation, and it's possible that you're implementing a dynamic proxy with a Python-like approach. However, since the Proxy
class does not know what kind of dynamic proxy class is needed until the interface class is specified in the argument of the newProxyInstnce
method, it is interpreted as creating a new class in the newProxyInstnce
method. I have.
[^ 2]: This is an extreme argument, but you should always consider using dynamic proxies carefully enough to suspect that you may fall into anti-patterns.