Why Spring-proxy uses delegate pattern instead of inheritance+super? - java

As we all know, the self-invokation of bean's method is not working in Spring without AspectJ.
See this question for example.
I think this is because the Spring-created proxy calls the target object's methods using delagate pattern. Like this:
class MyClass {
#Autowired
private MyClass self; // actually a MyProxy instance
#Transactional // or any other proxy magic
public void myMethod() {}
public void myOtherMethod() {
this.myMethod(); // or self.myMethod() to avoid self-invokation problem
}
}
class MyProxy extends MyClass { // or implements MyInterface if proxyMode is not TARGET_CLASS and MyClass also implements MyInterface
private final MyClass delegate;
#Override
public void myMethod() {
// some proxy magic: caching, transaction management etc
delegate.myMethod();
// some proxy magic: caching, transaction management etc
}
#Override
public void myOtherMethod() {
delegate.myOtherMethod();
}
}
Am I right?
With this code:
public void myOtherMethod() {
this.myMethod();
}
this.myMethod() will bypass the proxy (so all #Transactional or #Cacheable magic) because it is just internal delegate's call... So we should inject a MyClass bean (which is actually is MyProxy instance) inside MyClass and call self.myMethod() instead. It is understandable.
But why the proxy is implemented this way?
Why it is not just extends the target class, overriding all public methods and calling super instead of delegate?
Like this:
class MyProxy extends MyClass {
// private final MyClass delegate; // no delegate
#Override
public void myMethod() {
// some proxy magic: caching, transaction management etc
super.myMethod();
// some proxy magic: caching, transaction management etc
}
#Override
public void myOtherMethod() {
super.myOtherMethod();
}
}
It should solve the self-invokation problem, where this.myMethod() bypasses the proxy, because in this case this.myMethod(), invoked from MyClass.myOtherMethod() (we remember that MyClass bean actually is MyProxy instance), will invoke overriden child's method (MyProxy.myMethod()).
So, my main question is why it is not implemented this way?

Your assumption that Spring AOP uses delegation for its proxies is correct. This is also documented.
Using CGLIB, you can theoretically use proxy.invokeSuper() in order to achieve the effect you want, i.e. that self-invocation is registered by the aspect implemented by the proxy's method interceptor (I am using Spring's embedded version of CGLIB here, thus the package names):
package spring.aop;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
class SampleClass {
public void x() {
System.out.println("x");
y();
}
public void y() {
System.out.println("y");
}
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
#Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
if(method.getDeclaringClass() == Object.class)
return proxy.invokeSuper(obj, args);
System.out.println("Before proxy.invokeSuper " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After proxy.invokeSuper " + method.getName());
return result;
}
});
SampleClass proxy = (SampleClass) enhancer.create();
proxy.x();
}
}
Console log:
Before proxy.invokeSuper x
x
Before proxy.invokeSuper y
y
After proxy.invokeSuper y
After proxy.invokeSuper x
This is exactly what you want. The problem starts, however, when you have several aspects: transactions, logging, whatever else. How do you make sure that they all work together?
Option 1: Each aspect gets its own proxy. This obviously will not work unless you nest the proxies into each other according to aspect precedence. But nesting them into each other means inheritance, i.e. one proxy would have to inherit from the other outside-in. Try proxying a CGLIB proxy, it does not work, you get exceptions. Furthermore, CGLIB proxies are quite expensive and use perm-gen memory, see descriptions in this CGLIB primer.
Option 2: Use composition instead of inheritance. Composition is more flexible. Having one proxy to which you can register aspects as needed solves the inheritance problem, but also means delegation: The proxy registers the aspects and calls their methods during runtime in the right order before/after the actual real object's code is executed (or not, if an #Around advice never calls proceed()). See this example from the Spring manual about manually registering aspects to a proxy:
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an #AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object supplied must be an #AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();
As to why the Spring developers chose this approach and whether it might have been possible to use the one-proxy approach but still make sure that self-invocation works like in my little CGLIB sample "logging aspect" above, I can only speculate. You can maybe ask them on the developers mailing list or look into the source code. Maybe the reason was that CGLIB proxies should behave similarly to the default Java dynamic proxies so as to make switching between the two for interface types seamless. Maybe the reason is another one.
I did not mean to be rude in my comments, only straightforward, because your question is really not suited to StackOverflow because it is not a technical problem to which someone can find a solution. It is a historical design question and rather philosophic in nature because with AspectJ a solution to your technical problem (self-invocation) beneath the actual question already exists. But maybe you still want to dive into the Spring source code, change the Spring AOP implementation from delegation to proxy.invokeSuper() and file a pull request. I am not sure such a breaking change would be accepted, though.

In addition, you will not able to use Inheritance + super in the following cases:
What about if the RealSubject is final, so the proxy will can NOT extends it
What about if the Proxy needs to extend something other than the RealSubject
What about if you need to hide some functionality (methods) inside the RealSubject
Prefer Composition over Inheritance (recommended by many developers)

Related

How can i restrict my clients with selected methods from the class?

Let's say I have 1 complete class with around 20 methods which provide different functionalities.
Now we have multiple clients using this class, but we want them to have restricted access.
For e.g. -
Client 1 - Gets access to method1/m3/m5/m7/m9/m11
Client 2 - Gets access to method2/m4/m6/m8/m10/m12
Is there any way I can restrict this access?
One solution which I thought:
Create 2 new classes extending Parent class and override methods which are not accessible and throw Exception from them.
But then if 3rd client with different requirement, we have to create new subclass for them.
Is there any other way to do this?
Create 2 new classes extending Parent class and override methods which
are not accessible and throw Exception from them. But then if 3rd
client with different requirement, we have to create new subclass for
them.
It is a bad solution because it violates Polymorphism and the Liskov Substitution Principle. This way will make your code less clear.
At first, you should think about your class, are you sure that it isn't overloaded by methods? Are you sure that all of those methods relate to one abstraction? Perhaps, there is a sense to separate methods to different abstractions and classes?
If there is a point in the existence of those methods in the class then you should use different interfaces to different clients. For example, you can make two interfaces for each client
interface InterfaceForClient1 {
public void m1();
public void m3();
public void m5();
public void m7();
public void m9();
public void m11();
}
interface InterfaceForClient2 {
public void m2();
public void m4();
public void m6();
public void m8();
public void m10();
public void m12();
}
And implement them in your class
class MyClass implements InterfaceForClient1, InterfaceForClient2 {
}
After it, clients must use those interfaces instead of the concrete implementation of the class to implement own logic.
You can create an Interface1 which defines methods only for Client1, and an Interface2 which defines methods only for Client2. Then, your class implements Interface1 and Interface2.
When you declare Client1 you can do something like: Interface1 client1.
With this approach, client1 can accesses only methods of this interface.
I hope this will help you.
The other answers already present the idiomatic approach. Another idea is a dynamic proxy decorating the API with an access check.
In essence, you generate a proxy API that has additional checks on method calls to implement a form of Access Control.
Example Implementation:
package com.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
#FunctionalInterface
public interface ACL<P, Q> {
boolean allowed(P accessor, Q target, Method method, Object[] args);
class ACLException extends RuntimeException {
ACLException(String message) {
super(message);
}
}
#SuppressWarnings("unchecked")
default Q protect(P accessor, Q delegate, Class<Q> dType) {
if (!dType.isInterface()) {
throw new IllegalArgumentException("Delegate type must be an Interface type");
}
final InvocationHandler handler = (proxy, method, args) -> {
if (allowed(accessor, delegate, method, args)) {
try {
return method.invoke(delegate, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
} else {
throw new ACLException("Access denies as per ACL");
}
};
return (Q) Proxy.newProxyInstance(dType.getClassLoader(), new Class[]{dType}, handler);
}
}
Example Usage:
package com.example;
import java.lang.reflect.Method;
public class Main {
interface API {
void doAlpha(int arg);
void doBeta(String arg);
void doGamma(Object arg);
}
static class MyAPI implements API {
#Override
public void doAlpha(int arg) {
System.out.println("Alpha");
}
#Override
public void doBeta(String arg) {
System.out.println("Beta");
}
#Override
public void doGamma(Object arg) {
System.out.println("Gamma");
}
}
static class AlphaClient {
void use(API api) {
api.doAlpha(100);
api.doBeta("100");
api.doGamma(this);
}
}
public static class MyACL implements ACL<AlphaClient, API> {
#Override
public boolean allowed(AlphaClient accessor, API target, Method method, Object[] args) {
final String callerName = accessor.getClass().getName().toLowerCase();
final String methodName = method.getName().toLowerCase().replace("do", "");
return callerName.contains(methodName);
}
}
public static void main(String[] args) {
final MyACL acl = new MyACL();
final API api = new MyAPI();
final AlphaClient client = new AlphaClient();
final API guardedAPI = acl.protect(client, api, API.class);
client.use(guardedAPI);
}
}
Notes:
The accessor does not have to be the client object itself, it can be a string key or token that helps ACL identify the client.
The ACL implementation here is rudimentary, more interesting ones could be One that reads ACL from some file or One that uses method and client annotations as rules.
If you don't want to define an interface for API class, consider a tool like javassist to directly proxy a class.
Consider other popular Aspect Oriented Programming solutions
You should create one super class with all the methods and then provide Client specific implementations in their corresponding sub classes extending from the super class defined earlier.
If there are methods which are common implementation for all clients, leave their implementations to the super class.
It seems like you are a bit confused about the purpose of Classes and Interfaces. As far as I know, an Interface is a contract defining which functionality a piece of software provides. This is from official java tutorial:
There are a number of situations in software engineering when it is
important for disparate groups of programmers to agree to a "contract"
that spells out how their software interacts. Each group should be
able to write their code without any knowledge of how the other
group's code is written. Generally speaking, interfaces are such
contracts.
Then you can write a Class which implements this Interface/contract, that is, provides the code that actually perform what was specified. The List interface and the ArrayList class are both an example of this.
Interfaces and Classes have access modifiers, but they aren't designed to specify permissions to specific clients. They specify what is visible for other piece of software depending the location where it is defined: Class, Package, Subclass, World. For example, a private method can be accessed only inside the class where it is defined.
From official Java tutorial again:
Access level modifiers determine whether other classes can use a
particular field or invoke a particular method. There are two levels
of access control:
At the top level—public, or package-private (no explicit modifier).
At the member level—public, private, protected, or package-private (no
explicit modifier).
Maybe you want something more powerful like Access Control List (ACL).
Your question is a little unclear, leading to different possible answers. I'll try to cover some of the possible areas:
Object encapsulation
If your goal is to provide interfaces to different clients that only provide certain functionality or a specific view there are several solutions. Which matches best depends on the purpose of your class:
Refactoring
The question somehow suggests that your class is responsible for different tasks. That might be an indicator, that you could tear it apart into distinct classes that provide the different interfaces.
Original
class AllInOne {
A m1() {}
B m2() {}
C m3() {}
}
client1.useClass(allInOneInstance);
client2.useClass(allInOneInstance);
client3.useClass(allInOneInstance);
Derived
class One {
A m1() {}
}
class Two {
B m2() {}
}
class Three {
C m3() {}
}
client1.useClass(oneInstance);
client2.useClass(twoInstance);
client3.useClass(threeInstance);
Interfaces
If you choose to keep the class together (there might be good reasons for it), you could have the class implement interfaces that model the view required by different clients. By passing instances of the appropriate interface to the clients they will not see the full class interface:
Example
class AllInOne implements I1, I2, I3 {
...
}
interface I1 {
A m1();
}
But be aware that clients will still be able to cast to the full class like ((AllInOne) i1Instance).m2().
Inheritance
This was already outline in other answers. I'll therefore skip this here. I don't think this is a good solution as it might easily break in a lot of scenarios.
Delegation
If casting is a risk to you, you can create classes that only offer the desired interface and delegate to the actual implementation:
Example
class Delegate1 {
private AllInOne allInOne;
public A m1() {
return allInOne.m1();
}
}
Implementing this can be done in various ways and depends on your environment like explicit classes, dynamic proxies , code generation, ...
Framework
If you are using an Application Framework like Spring you might be able to use functionality from this Framework.
Aspects
AOP allows you to intercept method calls and therefor apply some access control logic there.
Security
Please note that all of the above solutions will not give you actual security. Using casts, reflection or other techniques will still allow clients to obtain access to the full functionality.
If you require stronger access limitations there are techniques that I will just briefly outline as they might depend on your environment and are more complex.
Class Loader
Using different class loaders you can make sure that parts of your code have no access to class definitions outsider their scope (used e.g. in tomcat to isolate different deployments).
SecurityManager
Java offers possibilities to implement your own SecurityManager this offers ways to add some extra level of access checking.
Custom build Security
Of course you can add your own access checking logic. Yet I don't think this will be a viable solution for in JVM method access.

Spring AOP is powerless for classes with interfaces

I understand that Spring AOP is very limited in its abilities (it can only cut into public methods of classes that are Spring beans, and only when those methods are called from outside the class). But now I've discovered another baffling limitation when interfaces are involved.
Normally, if a class is subclassed, Spring AOP has no problem cutting into all of their methods (even overridden ones):
public class A {
public void methodA() { } //OK, can cut in
}
public class B extends A {
#Override
public void methodA() { } //OK, can cut in
public void methodB() { } //OK, can cut in
}
But when we add an interface into the mix, things get pretty bad for Spring AOP:
public interface I {
public void methodA();
}
public class A implements I {
#Override
public void methodA() { } //OK, can cut in
public void methodB() { } //Fail, cannot see or cut into this method
}
public class B extends A {
#Override
public void methodA() { } //Fail, cannot see or cut into this method
public void methodC() { } //Fail, cannot see or cut into this method
}
First of all, Spring AOP can only cut into methods that are in the interface, anything else - it cannot see. Second, it can only cut into the method that directly implements the interface's method - A.methodA(). It cannot cut into the same method overridden by B.
I am using a generic pointcut expression "execution(* method*(..))" to cut into all possible methods, so it's not an expression issue.
Is there any way around this limitation? Or should I just forget about Spring AOP and use a different approach?
UPDATE:
Ok, I have found the real cause of the problem. I was actually relying on Intellij IDEA's AOP plugin to test this. It's supposed to link the pointcut to all affected methods. But it was using the 'old', dynamic JDK proxy strategy instead of the new, CGLIB strategy. So it wasn't linking it to all methods, but when I actually ran my program, it would cut into all methods correctly.
I'm using Spring Boot 2, which uses the 'new' CGLIB strategy. But on SB1 it might still use the 'old' dynamic JDK proxy strategy, so it might still not work there.
Spring will use either dynamic proxy or cglib to implement AOP.
Cglib is picked if there is no interface, then it will effectively create a subclass of the target class, and override all methods in the target class. With this way all methods could be cut in, except final and static ones.
In case the target class is with interface, then Spring might use a dynamic proxy using one of the interface, and apprantly this will only affect the methods declared in the interface.
Before spring-boot 2.0, dynamic proxy is the default strategy. Now Cglib is the default strategy after spring-boot 2.0.
It seems to me spring probably take the dynamic proxy approach in your case. You could add spring.aop.proxy-target-class: true in your application.yaml to force use Cglib.
In case you still have issue, it's better to post more complete code snippet showing how the mothods are invoked.

How to "proxy" a method in Java

First off, I'm not sure how to best word my solution so if I seem to be babbling at times then please consider this.
There is an interface in a library I wish to modify without touching the physical code,
public interface ProxiedPlayer {
// .. other code
public void setPermission(String permission, boolean state);
}
I have written a third party library for handling permissions and having to hook into my API to edit permissions may be a step some developers do not want to take. So I ask that when setPermission is called is it possible to have it invoke my invoke the appropriate method in my library that will handle permission setting whilst ignoring the pre-programmed code or not?
Here is the full interface I am attempting to proxy.
I have looked into the Java Proxy class but it seems you need an instance of the object you're trying to proxy in the first place. Given that the method can be called any time I do not believe this to be my solution but will happily stand corrected.
I do not have control over instantiation of classes implementing the ProxiedPlayer interface.
EDIT: Ignorant me, there several events that I can subscribe to where it is possible to get an instance of the player, would this be the appropriate place to attempt to proxy the method? One of these events is fired when a player joins the server and getting the instance of the player is possible.
Would the Proxy code need to be called for every instance of the ProxiedPlayer interface or is it possible to simply proxy every invocation of the method in an easier way?
My library is a plugin loaded after everything else that is essential has finished loading.
Edit #2:
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class InvocationProxy implements InvocationHandler {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ProxiedPlayer player = (ProxiedPlayer) proxy;
if(method.getName().equals("setPermission")) {
// Call my code here?
}
return method.invoke(player, args);
}
}
Would something along the lines of what I have above work or am I barking up the wrong tree entirely?
If you do not want to touch the original source, then you only solve this problem by using a Java agent that redefines any class that implements the ProxiedPlayer interface to enforce your security check before calling the actual method. AspectJ together with a load-time-weaving agent was already mentioned as a possible solution for this but you can also implement a pure Java solution using my library Byte Buddy:
public class InterceptionAgent {
public static void premain(String arguments,
Instrumentation instrumentation) {
new AgentBuilder.Default()
.rebase(isSubtypeOf(ProxiedPlayer.class))
.transform(new AgentBuilder.Transformer() {
#Override
public DynamicType.Builder transform(DynamicType.Builder builder) {
return builder.method(named("setPermission"))
.intercept(MethodDelegation.to(MyInterceptor.class)
.andThen(SuperMethodInvocation.INSTANCE));
}
}).installOn(instrumentation);
}
}
With this agent, you more or less specify that you want to redefine any class that is a subtype of ProxiedPlayer to redefine (any) method named setPermisson in order to call a MyInterceptor (that would be your code) and to subsequently call the original implementation.
Note that the suggested implementation assumes that all classes implementing ProxiedPlayer implement the method of this interface and that there is only a single method of this signature. This might be too simple but it shows what direction to go.

Spring:DI with interface with implementation class less restrictive exceptions

I have an implementation class which catches all the declared exceptions of a method of an Interface. As I inject and use the Interface instance variable inside a class and hope to call the implementation method - I am naturally getting a compiler error pointing that I either need to throw/catch the exceptions declared in parent.
Few options that come to my mind are these, but I don't like them. Just want to know the best way to go about this.
Cast the interface instance to impl
Create child interface with a method with no exceptions
May be just not declare exceptions in Interface. Just catch all of the possible exceptions in impl.
EDIT 1: Attached some example code
public interface ServiceUtilInterface {
public abstract String getMessage(String ID) throws CustomException;
}
#Component(value="MyServiceUtil")
public class MyServiceUtil implements ServiceUtilInterface {
#Override
public String getMessage(String ID) {
try{
//do something
}catch(CustomException e){
}
return "";
}
#Component
public class Usage {
#Autowired
ServiceUtilInterface serviceUtil;
public void someMethod(){
serviceUtil.getMessage("123");
//This where compiler expects me to throw /catch the exception defined in interface
}
}
UPDATE
Cast the interface instance to impl - never ever do that. If you use Spring then you never know what the implementation of an interface could be. This should be configuration dependent.
If you start do write jUnits you will probably need to use mock (fake) components for testing. Then if you try to cast your mock to a concrete implementation your code will fail. In other words you will never be able to write proper unit tests. The other thing is that if you add some Aspects or make a service #Transactional or #Validated then you wont be able to cast because instead of your implementation you may receive a proxy object.
and 3 that strongly depends on your code design. Try to find some materials about good practices for throwing and handling exceptions. There are some general rules about that. Probably no one can help you with this because this is service specific.

Listening for when a method is called in a class, and then possibly overriding it (java)

So, let's say I have 2 classes, Foo1 and Foo2, which is in a separate library.
Foo2 is a class that is already instantiated, and I cannot correctly reinstintate it as a subclass to override a method in Foo2.
Is there any way I can listen to a certain method that is called in Foo2, and then possibly cancel the execution of said method, and from there create another method. I understand if what I"m saying is confusing, hopefully I can get some help :).
class Foo{
void x(){
if (Foo2.x2().called){
//do stuff
}
}
}
class Foo2{
void x2(){
//Stuff done here...
}
}
Obviously, the above code won't do anything, it is just simple an example of what I am looking for.
you need a proxy on that object, and an interceptor on the method. There are a couple of ways to do it:
If you have an interface you can use reflection and proxies and invocation handlers docs.oracle.com/javase/6/docs/api/java/lang/reflect/Proxy.html.
If you have a concrete class you can use CGLIB cglib.sourceforge.net to create an enhancer for your class
If you are using Spring you can use the AOP http://static.springsource.org/spring/docs/2.5.5/reference/aop.html.
You can also use AspectJ http://www.eclipse.org/aspectj/doc/next/progguide/ to do the same
Cheers!
If you can't somehow subclass Foo2 or modify the existing lib (in worst case you could decompile/modify/recompile) you could use aspectj to intercept calls.
You'd probably want to use load-time weaving for this purpose. Check out the general documentation for load-time weaving here: http://www.eclipse.org/aspectj/doc/next/devguide/ltw.html. It's a fairly involved procedure to add/configure aspectj though so I'd only recommend it as a last resort
Depending on what you're trying to do, this might work:
If you had a boolean isX2Called in class Foo, when x2() is called, set isX2Called to true. Then in x(), you can check if isX2Called is true. If you ever want to reset, you can set isX2Called back to false. This might not work for all purposes though.
In my opinion, to solve this issue you could use a third class to act as a Decorator/Proxy.
For instance, you can do something like:
class FooManager {
private Foo1 f1;
private Foo2 f2;
private boolean canExecuteFooMethods(){
// Evaluate if should run any Foo1 or Foo2 method
}
public void foo1Method(){
if(canExecuteFooMethods()){
f1.x();
}
}
public void foo2Method(){
if(canExecuteFooMethods()){
f2.x();
}
}
}
Assuming that you can subclass the type, the following code would work perfectly:
Foo foo = new Foo() {
#Override
public void someMethod() {
super.someMethod();
//your logic here (listen, hook, spy, override, etc)
}
}

Categories

Resources