I'm writing some methods to deal with database operations. Each method first gets a connection, do the operations, and close the connection at end.
I wonder if Spring AOP can help handling the connection acquiring and closing. Specifically I want something like:
#Aspect
#Component
public class ConnAspect {
#Around("#annotation(connHandle)")
public void handleConnection(ProceedingJoinPoint pjp, ConnHandle connHandle) throws Throwable {
Connection conn = datasource.getConnection();
pjp.proceed(); // can pjp get variable conn?
conn.close();
}
}
#Component
public class DbOperation {
#ConnHandle
public void operation1(...) {
... // do some operation with conn
}
...
}
Is it possible to do so? Or should I turn to other solutions? Thanks for any hints and answers.
No, this is not possible, and the suggestions in the comments are not going to help you. You cannot magically inject a non-existent method parameter or local variable into a method. Besides, what you are trying to do is anti AOP: not to encapsulate your cross-cutting concern in an aspect, but somehow bleed aspect context into your application, which ideally should be unaware of the aspect and work without it. You should rather describe what you want to achieve instead of being fixated on a specific (bad) design you have dreamed up to implement your idea.
Besides, there are simpler, reflective ways for a method to fetch its own annotations than to abuse AOP for that purpose.
Related
i have a little kont in my brain about structuring our code. We have a REST Backend based on SpringBoot. To handle requests regarding to security checks we use HandlerInterceptors. In some specific cases we need a specific interceptor and not our default one. The default one is registered in a 3rd party lib that no one can forget it. But i want all coders to think about this specific interceptor.
Actually, i just said it to them to achieve this.
Here's my question: Is there an option to create required (or necessary) interfaces which must be implemented? This would be a way to provide our security code by lib and to have the security that every coder implemented our specific interface (also if he just does nothing with it).
pseudo code:
public interface thinkForIt(){
Object SecBean specificSecBean;
public void methodToThinkOn();
}
public SecImpl implements thinkForIt(){
#Override
public void methodToThinkOn(){
return null; // i thought about it but i do not need to do anyting!
}
If the interface thinkForIt would have any annotations like #required, users could get warning or error if they did not implement it...
Looking for a solution and thanks for your comments in advance!
Your overall design is questionable; you are reinventing security code, which is always a red flag. Use Spring Security instead.
However, there's a simple way to ensure that "some bean of type Foo" has been registered with the context:
#Component
#RequiredArgsConstructor
public class ContextConfigurationVerifier {
final Foo required;
}
I'd like to learn if there are some rules / conditions that a Spring component is wrapped (proxied) by CGLIB. For example, take this case:
#Component
public class TestComponent {
}
#Service
//#Transactional(rollbackFor = Throwable.class)
public class ProcessComponent {
#Autowired
private TestComponent testComponent;
public void doSomething(int key) {
// try to debug "testComponent" instance here ...
}
}
If we let it like this and debug the testComponent field inside the method, then we'll see that it's not wrapped by CGLIB.
Now if we uncomment the #Transactional annotation and debug, we'll find that the instance is wrapped: it's of type ProcessComponent$$EnhancerByCGLIB$$14456 or something like that. It's clearly because Spring needs to create a proxy class to handle the transaction support.
But I'm wondering, is there any way that we can detect how and when does this wrapping happen ? For example, some specific locations in Spring's source code to debug into to find more information; or some documentations on the rules of how they decide to create a proxy.
For your information, I need to know about this because I'm facing a situation where some component (not #Transactional, above example is just for demonstrating purpose) in my application suddenly becomes proxied (I found a revision a bit in the past where it is not). The most important issue is that this'll affect such components that also contain public final methods and another issue (also of importance) is that there must have been some unexpected changes in the design / structure of classes. For these kind of issues, of course we must try to find out what happened / who did the change that led to this etc...
One note is that we have just upgraded our application from Spring Boot 2.1.0RELEASE to 2.1.10RELEASE. And checking the code revision by revision up till now is not feasible, because there have been quite a lot of commits.
Any kind of help would be appreciated, thanks in advance.
You could debug into org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(Class, String, TargetSource).
If any advisor is found, the bean will be proxied.
If you use a #Lookup method injection it will also proxy the component class.
I'd like to decorate the interface PreparedStatement, in order to custom close it (just an example).
This means that I want to decorate an existing instance of PreparedStatement, thus, invoking other code, when close() is being invoked.
For that, I need to default implement all tens of methods of PreparedStatement decorator just to delegate the calls to the inner object, like done here. The downfall is that it's just a lot of work and code with little added value.
Another option is to try and use Java's Proxy and InvocationHandler in order to provide a default implementation that does the delegate for all the methods in a single method. If a custom method exists, the InvocationHandler, directs the call to it. See example here.
The problem with this solution is that the custom method cannot be marked as #Override and its signature cannot be checked for correctness, as it will require an abstract PreparedStatement, which the Proxy will not be able to instantiate.
So, can this be done? How?
* Must be able to implement using Java 7 max, but feel free to provide Java 8 answers.
As far as I understood you want to provide to the interface PreparedStatement concrete implementation. The only way I can think of is by creating abstract class that implements the interface. By doing so you don't need to implement all the methods from the interface and you'll have your desired implementation.
I'd try something like this:
public abstract class MyPreparedStatement implements PreparedStatement {
#Override
public void close() throws SQLException {
System.out.println("Closing");
}
public static void main(String[] args) throws SQLException {
Connection con = null;
MyPreparedStatement statement = (MyPreparedStatement) con.prepareStatement("sql");
}
}
Can you explain in clearer terms what the Proxy solution is lacking? Consider something like this, which relies on a AOP-esque 'hook':
final PreparedStatement original = ...;
final InvocationHandler delegator = new InvocationHandler() {
void onClose() {
/* do stuff */
}
Object invoke(final Object proxy, final Method method, final Object[] args) {
if (method.getName().equals("close")) {
onClose();
}
return method.invoke(original, args);
}
};
final PreparedStatement wrapped = (PreparedStatement) Proxy.newProxyInstance(this.getClass().getClassLoader(),
new Class<?>[] { PreparedStatement.class }, delegator);
If you don't have access to the methods in order to do the usual inheritance thing with them, you can accomplish what you are attempting to do with Aspect Oriented Programming, leveraging AspectJ or the Spring Framework aspect functionality to provide advice on your desired methods.
A simple aspect basically comes down to:
#Aspect
public class MyAspect {
#Pointcut("execution(* *(..))") //Replace expression with target method; this example
//will hit literally every method ever.
public void targetmethod() {}; //Intentionally blank.
//AspectJ uses byte code manipulation (or "black magic voodoo", if you
// will) to make this method a surrogate for any real one that matches the pointcut
#Before("targetmethod()") //Or #After, or #Around, etc...
public void doStuff() throws Throwable {
//Put your code here
}
}
Once you have your aspects together, add them to your aop.xml and weave your aspects (you can do this at compile time with appropriate build manager configuration, or at run time by running aspectjweaver with java -javaagent:/path/to/aspectjweaver.jar).
This does come with a disclaimer however: doing things like this to java.* classes allows you break things in new and interesting ways with all the side-effects you're introducing (in fact, AspectJWeaver refuses to weave into java.* classes by default, though you can override that setting). Be very aware of what you are doing, and use your aspects and aspected methods wisely.
Let say I use JPA by using #transactions annotations.
So to have any method run under a transaction I add a #transaction annotations and BINGO my method run under a transaction.
To achieve the above we need have a interface for the class and the instance is managed by some container.
Also I should always call the method from interface reference so that the proxy object can start the transaction.
So My code will look like:
class Bar {
#Inject
private FooI foo;
...
void doWork() {
foo.methodThatRunUnderTx();
}
}
class FooImpl implements FooI {
#Override
#Transaction
public void methodThatRunUnderTx() {
// code run with jpa context and transaction open
}
}
interface FooI {
void methodThatRunUnderTx();
}
Well and Good
Now let say methodThatRunUnderTx does two logic operations
[1] call some service(long request/response cycle let say 5 sec) and fetch the results
[2] perform some jpa entity modifications
Now since this method call is long and we don't want to hold the transaction open for long time, so we change the code so that [2] happens in separate tx and methodThatRunUnderTx doesnt run in transaction
So we will remove the #Transaction from the methodThatRunUnderTx and add another method in class with #transaction let say new methods is methodThatRunUnderTx2, now to call this method from methodThatRunUnderTx we have to inject it into itself and add a method to interface so that the call happen through proxy object.
So now our code will look like:
class Bar {
#Inject
private FooI foo;
...
void doWork() {
foo.methodThatRunUnderTx();
}
}
class FooImpl implements FooI {
#Inject
private FooI self;
#Override
//#Transaction -- remove transaction from here
public void methodThatRunUnderTx() {
...
self.methodThatRunUnderTx2();// call through proxy object
}
#Override
#Transaction //add transaction from here
public void methodThatRunUnderTx2() {
// code run with jpa context and transaction open
}
}
interface FooI {
void methodThatRunUnderTx();
void methodThatRunUnderTx2();
}
NOW The Problem
We have made methodThatRunUnderTx2() to be public through interface.
But it is not what we want to expose as our api of FooI and not meant to be called from outside..
Any suggestion to solve it ?
That's why modern containers don't require any interface to be implemented - proxies are then created by dynamic subclassing or bytecode instrumentation is used.
So, the solution to your design issue is simple: Implement a helper class containing the transactional method and inject it to the class implementing the interface (and to any other class that can benefit from it).
Following the Interface Segregation Principle, separate the two logic operations into two interfaces: a fetcher and a modifier. Inject both into class Bar. This allows the two logic implementations to change independently of each other, for example allowing one to be transactional while the other is not. The second interface need not be a public class.
The question is a very valid one on handling the Transaction part. However, if you are trying to hide one functionality over other, you need to consider these :
OPTION 1 :
Considering - You would need to expose the method that does the whole functionality required by the caller
In this case of transaction handling, I would suggest you to keep the transaction open for the time being till it completes
OPTION 2:
Considering - You would need to efficiently manage transactions
Split the interface's methods based on Functionality IModifyFoo and ISelectFoo that does modify and select respectively and implement the methods and annotate with #Transactional on required methods
Interfaces are designed to be public that means that you need to be aware of what you need to expose to external world. In this scenario, you are posed to choose Principle over the technical challenge.
I can just think of these options and we are trying to address your technical challenge here that resides on basics of java. Good one to think about.
As you said, if you call a method on the same bean it'll not be proxied therefore no transaction management will happens, to solve it you can you Bean Managed Transaction where you manually start and stop the transaction:
class FooImpl implements FooI {
#Resource
private UserTransaction userTransaction;
#Override
//#Transaction -- remove transaction from here
public void methodThatRunUnderTx() {
...
self.methodThatRunUnderTx2();// call through proxy object
}
#Override
//#Transaction -- remove transaction from here too, because now you'll manage the transaction
public void methodThatRunUnderTx2() {
userTransaction.start();
// code run with jpa context and transaction open
userTransaction.commit(); // Commit or rollback do all the handling, i'm not writing it because its just an example
}
}
That way you are not exposing anything extra to public api, but you'll have a little extra code to manage the transaction.
if you want that methodThatRunUnderTx2 does not become public make it a private method and remove #Override annotation and remove it from interface.
You have to accept that transaction-based annotations won't work on private methods. So you simply cannot hide (make private) a method that is supposed to be a subject of that kind of annotation.
You can get rid of interfaces (i.e. #LocalBean in EJB world), but still, you cannot use private method...
For sure the solution for this problem are acpects. They would allow to get rid of self.methodThatRunUnderTx2() method call from the body of public void methodThatRunUnderTx(). Most probably the answer for this question could help you: Aspectj and catching private or inner methods
I'm not sure however if aspects are not too big gun for this problem, as they increase complexity and readability of code. I would rather think about changing architecture of your code in such a way, that your problem would not matter.
I am working on a program that uses Spring and obtains Hibernate transactions transparently using a TransactionInterceptor. This makes it very convenient to say "when this method is invoked from some other class, wrap it in a transaction if it's not already in one."
However, I have a class that needs to attempt a write and must find out immediately whether or not it has succeeded. While I want two methods anyway, I was hoping that there was a way to keep them in the same class without needing to explicitly create an transaction procedurally. In effect, I'd like something like this:
public void methodOne() {
//..do some stuff
try {
transactionalMethod();//won't do what I want
} catch(OptimisticLockingFailure e) {
//..recover
}
}
#Transactional
public void transactionalMethod() {
//...do some stuff to database
}
Unfortunately, as I understand it, this wouldn't work because I'd just be directly calling transactionalMethod. Is there a way to ask Spring to call a local method for me and wrap it in a transaction if needed, or does it have to be in another class that I wire to this one?
Define an interface which the class implements which does the transactionalMethod(); use dependency injection to set the class' value of that to its own implementation; in your bean factory, allow Spring to insert an Around aspect around that interface implementation. That should work for your needs.
If you want the transactionalMethod to be part of it's own transaction and not simply join onto the transaction that is already active you have to set the propagation to REQUIRES_NEW. Like so
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void transactionalMethod() {
//...do some stuff to database
}
You should also check that your transaction manager supports this propagation. the means that transactionalMethos is completely seperate from the other transaction that it was called from and it will commit / rollback completely seperately as well.