What is the responsibity of the proxy class in AOP? What is the role of that?
Dynamic proxies are used to execute additional code before/after methods of your beans. The most trivial example is transaction handling:
spring creates a proxy around your beans that need transactions
if a method is declared transactiona (e.g. annotated with #Transactional) the proxy starts a new transaction and delegates to the real method
the real method executes and returns
the proxy now commits (or rollbacks) the transaction
Thus your code becomes transaction-agnostic. And when a transactional bean is injected into another one, it is actually the proxy that gets injected (which is of the same type as your bean)
And proxies are dynamic, because spring does not know at compile time the types of all your beans, so it has to create the proxies at runtime.
Related
I ran 2 examples in weblogic ( I used a bean with dependent scope):
1)the bean has not any interceptors or decorators: the bean was not proxied
2)the bean has a interceptors : the bean was proxied
I think that there are two types of proxies in CDI:
1)client proxy: This proxy overrides all the non-private methods of the bean class, when these overridden methods are invoked the proxy looks up the correct instance( or proxy of second type) of the bean and then forwards the invocation onto the actual bean instance (based on this link). for dependent scope this proxy is not created
2)there is another proxy for applying interceptors and decorators and it is created when the bean has decorator or interceptors
Is my assumption about second type of proxy correct? Does the specification say anything about it?
You made a nice investigation indeed and you are right for the most part.
Here are the details.
Proxy
Normal scoped beans (#ApplicationScoped, RequestScoped,...) are indeed proxied, you don't get hold of the actual instance and what you are getting is a client proxy.
With #Dependent which is not normal scoped, you basically want to inject new instance every time so there is no need to have it proxied.
The above has some mentions in CDI spec, albeit not precise to give implementation space in which they can manipulate - users should't really care if they have a proxy or not for calling their methods works just fine.
Interceptors and Decorators
Moving on to interceptors - spec says nothing about this from what I know and leaves implementations to choose freely what to do with it. Following details are Weld-specific although from what I recall, OWB has it similar. There aren't really many option how to achieve it anyway.
For every interceptor/decorator, there is a "proxy" created, in fact a subclass, which allows to make interception/decoration happen. This subclass replaces the original bean and all calls go through it (e.g. it is in the underlying bean store instead of the original instance).
Again, from user perspective, this makes no difference and you shouldn't be worried about it.
Extra tooling for proxies/sublasses
Sometimes, very rarely, and most likely only when you are developing a CDI library, you may truly need to see if the injected bean is a client proxy or a subclass.
Weld offers tools for that, every bean which has a client proxy is implementing WeldClientProxy interface from Weld API. This interface allows you to grab the actual instance and some metadata.
Likewise, every intercepted and decorated bean is implementing WeldContruct as a marker interface.
I am injecting EntityManager objects in stateless EJB3 beans (which act as DAO objects and each provide access to a different database table). Deployment is in JBoss AS 7.
I then added code using System.identityHashCode in the EJB3 beans methods to see the various instances of the EntityManagers injecting (hoping to see the same instance in all DAOs). E.g. like:
#Stateless
public class AFacade {
#PersistenceContext(unitName="foo")
EntityManager em;
public List<A> findAll() {
l.info("entity manager is: "+System.identityHashCode(em)+" class is: "+em.getClass().getSimpleName());
...
}
However, what I noticed is that each DAO (e.g. AFacade, BFacade and so on) was injected with a different EntityManager (as reported by identityHashCode) although the PersistenceContext was the same. The implementing class was TransactionScopedEntityManager in all cases.
It is not clear to me why this different EntityManager objects are injected, whether this is something that should concern me or not. Also, I understand that the EJB3 container may actually inject proxies to the real EntityManager so these different instances may actually be proxies to a single EntityManager.
Yes, they are proxies (in fact, I think they are thread safe decorators, rather than proxies) on the real entity managers.
I'm not sure if you know that the EntityManager is a wrapper around a connection. If you wouldn't have this decorator (or proxy), all invocations to that stateless bean would share the same connection (and potentially transaction), which is not what you want.
The injected EntityManagers are proxy generated by the EJB Containers.
For Transaction scoped Entity Managers, each transaction uses a single separate instance of Provider's Entity Manager.
When a method call is made to this proxy , container checks javax.transaction.TransactionSynchronizationRegistry ( this is implemented by EJB Container) to see if there is a provider EntityManager already created for this transaction. If not, it will create the provider Entity Manager and register it in TransactionSynchronizationRegistry and then delegate the method call to it. If already present, it will simply retrieve the provider Entity Manager an delegate the method call to it.
Transaction scoped EntityManagers are stateless according to the book "Pro JPA2 Mastering the Java Persistence API" by Mike Keith and Merrick Schincariol (See Chapter 6).
The proxy objects inserted in each EJB instance object is different, though a single proxy object could have been used because of the stateless nature of Transaction scoped Entity Manager.
Also take a look at : http://piotrnowicki.com/2011/11/am-i-in-the-same-transaction-am-i-using-the-same-persistencecontext/
If I have a service class which calls three other service classes in a row, and each of those sub-services has to deal with a DAO object at some point, how can I make so that the wrapper service wraps them all into a single transaction? Will it be as simple as annotating the wrapper with #Transactional? What if the DAO is already marked as #Transactional?
The default transaction propagation in Spring framework is REQUIRED, which means that the transaction is created if it does not already exist or the code joins existing one:
Support a current transaction, create a new one if none exists. Analogous to EJB transaction attribute of the same name.
This is the default setting of a transaction annotation.
This means that if you wrap calls to three transactional methods in a single transactional method, they will all run within a single transaction. Just like that.
See also:
What is the right way to use spring MVC with Hibernate in DAO, sevice layer architecture
If you annotate the outer service as #Transactional and your DAOs are also #Transactional and called by the service they will by default join the outer transaction as you're hoping.
this is actually a question about nested transaction (http://en.wikipedia.org/wiki/Nested_transaction). with spring, (assume you are using version 3 and annotation), REQUIRED is default for transaction mode. If you set this model for your service methods, all methods wrapped by your "wrapper" service will use the host transaction, which means they will run in same transaction.
I have a #SessionScoped? DAO that's being injected into a Stripes framework Interceptor constructor that seems to be found from the interceptor (on subsequent calls) but is not being injected into a service in the same request (and session). Why isn't the same instance (initialized in the interceptor) being reused in the service (which is in a different package in the same project)?
Making the DAO a #Singleton does the trick, but is unacceptable as the DAO stores information that must remain consistent throughout a user's session on an application that has multiple users who would be sharing the same DAO instance.
If the Interceptor is not a session-scoped object, then you'll need to inject Provider<YourDaoType> into the Interceptor. This is the common pattern to use when an object with a long life depends on another object with a shorter life.
ok, I've figured it out. I changed the #SessionScoped to a bind(DAO.class).in(ServletScopes.SESSION) statement with which the injection works. As far as I understand, these should be equivalent, but in my case they're producing different results.
One aspect that was troubling me along the way was that Stripes built the interceptor that injected the DAO on startup causing errors as this happened outside the scope of a session (which the DAO is #SessionScoped. ActionBeanContext context information is needed to initialize the DAO session context which I set in an AbstractActionBean setContext method that is called during the construction of the action bean.
Thanks for your interest and help.
I want to know that whether we can apply 'multiple' AOP behaviors to our service classes or not?
Lets just say, i do this to my BankServiceImpl class:
#Transactional on top of one of the method, accountTransfer(), and
and some custom <aop> pointcut on the execution of another method someOtherMethod().
Then will Spring be able to generate one proxy where accountTransfer() is made transactional and someOtherMethod() is also given aop behaviour?
Does any one has an idea on how Spring resolves multiple AOP behaviors?
It looks like Spring creates a single proxy object with all of the advice types in it. This proxy object will implement the org.springframework.aop.framework.Advised regardless of if it's a JDK dynamic proxy or a CGLIB proxy.
If you have multiple advisors, the order of their execution is undefined unless you make it explict by implementing the Ordered interface or the #Ordered annotation. You can find more on ordering here. Springs transactional aspects default to lowest priority.