In my Spring 4 application, I have a class like this:
class Address {
public getAdress(){
...
List<Town> towns = getTowns();
...
}
#CustomAnnotation
private List<Town> getTowns(){
}
}
With AspectJ I can easily intercept the getAdress() call.
The problem is with getTowns() that is not intercepted.
There are solutions such as Load-Time Weaving but that is difficult to tune and I don't what to reconfigure my application.
How can I capture any call made to any method annotated with CustomAnnotation without AspectJ ?
Regards
PS: I know that there is a workaround with self-reference but I don't find it very "clean".
Extracting interface:
interface TempIfc{
public getAdress();
}
class Address implements TempIfc{
#Override
public getAdress(){
...
List<Town> towns = getTowns();
...
}
#CustomAnnotation
private List<Town> getTowns(){
}
}
Adding config:
<bean id="tgt" class="Address">
<!-- your bean properties here -->
</bean>
<bean id="proxified" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="TempIfc"/>
<property name="target" ref="tgt"/>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
<bean id="myInterceptor" class="MyMethodInterceptor"/>
<!-- Example of usage with some service -->
<bean id="someYourService" class="Service">
<property name="adress" ref="proxified" />
</bean>
And finally interceptor:
public class MyMethodInterceptor implements org.aopalliance.intercept.MethodInterceptor{
public Object invoke(org.aopalliance.intercept.MethodInvocation invocation){
System.out.println("Before calling any TempIfc method ");
// Actionally, you may use getMethod, getArguments here to explore details, or modify arguments
Object result = invocation.proceed(); //also it is not obligatory to call real method
System.out.println("After calling any TempIfc method ");
//you may modify result of invocation here
return result;
}
}
Here is the docs and javadocs about ProxyFactoryBean.
I think we can use ControlFlowPointcut provided by Spring.
ControlFlowPointcut looks at stacktrace and matches the pointcut only if it finds a particular method in the stacktrace. essentially pointcut is matched only when a method is called in a particular context.
In this case, we can create a pointcut like
ControlFlowPointcut cf = new ControlFlowPointcut(MyClass.class, "method1");
now, using ProxyFactory create a proxy on MyClass instance and call method1().
In above case, only method2() will be advised since it is called from method1().
Related
I have the question. If my class has dependency like:
public class Test {
public Depend depend;
//Here methods
}
And it does not have setter for Depend property or constructor with Depend as argument, and it has no annotation for Spring but has xml config like:
<bean id="depend" class="xxx.Depend"></bean>
<bean id="test" class="xxx.Test">
<property name="depend" ref="depend" />
</bean>
Is it possible to inject Depend into Test using such config (actually his config does not work. I just wonder - can I change smth to make it work not using annotations or setter/constructor)?
It is not possible without using annotations.
Your current configuration needs some simple changes to make this work. Annotate the depend field with #Autowired and enable component scanning.
Here's a detailed explanation: http://www.mkyong.com/spring/spring-auto-scanning-components/
Yes it is possible without annotations, but you would need to create a TestBeanFactory and then create an object of Test and set Depend yourself before returning it.
<bean id="depend" class="xxx.Depend"></bean>
<bean id="testFactory" class="xxx.TestFactory">
<property name="depend" ref="depend" />
</bean>
<bean id="test" factory-bean="testFactory" factory-method="createTest">
</bean>
Then your test factory would look something like this.
public class TestFactory {
private Depend depend;
public setDepend(Depend depend) {
this.depend = depend
}
public Test createTest() {
Test test = new Test();
test.depend = this.depend;
return test;
}
}
I am stuck in a situation where there are many Action classes all of them extend from a parent class TPDispatchAction. Now I have to basically set a session spring bean everytime any action method is called wherein i set the tenant id of the user.
The crude way will be to add the line of code setting the value in all the action methods of all action classes.
Is there any better way to do this?
Edit
Solved the problem using MethodBeforeAdvice AOP
You can put an interceptor in front to set the bean in Session scope. Try implementing
org.springframework.web.servlet.HandlerInterceptor
to prehandle and posthandle of requests processing scenarios. You can set the tenantID in the prehandle method
You may want to create a method in the super class like
//super class A
A {
public foo(){
//create here whatever you want
bar();
}
protected bar();
}
//extending class/action
B:A{
bar(){
//your implementation
}
}
and whose call another method that is implemented by all other subclasses.
External object will only have to call and see the foo method, and there you will be able to to your initializations or postprocessing.
Suggestion Use PostConstruct to inject.
#PostConstruct
void initializeCommon() {
//set values here
}
I resolved my problem using Spring AOP MethodBeforeAdvice
public void before(Method methodName, Object[] arguments, Object arg2)
throws Throwable {
}
In this the methodName is the name of method which is called. arguments is the list of arguments of that method and arg2 is the returned object. So as HTTPRequest object is one of the objects in my action methods I am able to use the arguments and capture the session.
(Basically I have integrated Spring into my project which is Struts 1.3 based)
In applicationContext.xml
<bean name="globalInterceptor"
class="com.xyz.common.filters.GlobalRequestInterceptor"></bean>
<bean name="autoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>globalInterceptor</value>
</list>
</property>
</bean>
So this basically intercepts all the method calls in all the service beans.
Since the programmer is forced to catch all checked exception, I to throw checked exception in case of any problem. I would like to rollback on any of those expections. Writing rollbackFor=Exception.classon every #Transactional annotation is very error-prone, so I would like to tell spring, that: "whenever I write #Transactional, I mean #Transactional(rollbackFor=Exception.class)".
I know, that I could create a custom annotation, but that seems unnatural.
So is there a way to tell spring how it should handle checked excpetions globally?
Custom Shortcut Annotations
I know, that I could create a custom
annotation, but that seems unnatural.
No, this is exactly the use case for a Custom Annotation. Here's a quote from Custom Shortcut Annotations in the Spring Reference:
If you find you are repeatedly using
the same attributes with
#Transactional on many different
methods, then Spring's meta-annotation
support allows you to define custom
shortcut annotations for your specific
use cases.
Sample Code
And here's a sample annotation for your use case:
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Transactional(rollbackFor=Exception.class)
public #interface MyAnnotation {
}
Now annotate your services and / or methods with #MyAnnotation (you'll think of a better name). This is well-tested functionality that works by default. Why re-invent the wheel?
Approach with custom annotation looks good and straightforward, but if you actually don't want to use it, you can create a custom TransactionAttributeSource to modify interpretation of #Transactional:
public class RollbackForAllAnnotationTransactionAttributeSource
extends AnnotationTransactionAttributeSource {
#Override
protected TransactionAttribute determineTransactionAttribute(
AnnotatedElement ae) {
TransactionAttribute target = super.determineTransactionAttribute(ae);
if (target == null) return null;
else return new DelegatingTransactionAttribute(target) {
#Override
public boolean rollbackOn(Throwable ex) {
return true;
}
};
}
}
And instead of <tx:annotation-driven/> you configure it manually as follows (see source of AnnotationDrivenBeanDefinitionParser):
<bean id = "txAttributeSource"
class = "RollbackForAllAnnotationTransactionAttributeSource" />
<bean id = "txInterceptor"
class = "org.springframework.transaction.interceptor.TransactionInterceptor">
<property name = "transactionManagerBeanName" value = "transactionManager" />
<property name = "transactionAttributeSource" ref = "txAttributeSource" />
</bean>
<bean
class = "org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor">
<property name="transactionAttributeSource" ref = "txAttributeSource" />
<property name = "adviceBeanName" value = "txInterceptor" />
</bean>
Also you need <aop:config/> or <aop:aspectj-autoproxy />.
However note that such overrides may be confusing for other developers who expect a normal behaviour of #Transactional.
You can:
catch and wrap the checked exception into an unchecked exception - throw new RuntimeException(checkedException)
create a proxy around the method, using MethodInterceptor (or #AroundInvoke, or any other means to create aspects in spring), declare it to be executed before the <tx:annotation-driven /> by specifying order="1" and order="2" and catch and wrap there.
Looks like you can configure a transactional advice based on method name like this:
(from the Spring 2.0 docs)
Exactly which Exception types mark a transaction for rollback can be configured. Find below a snippet of XML configuration that demonstrates how one would configure rollback for a checked, application-specific Exception type.
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="false" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
I have a singleton bean which needs for each call of a function to return a reference to a different (new) prototype bean. The only way that I can think of doing this is to programmatically retrieve a new prototype bean instance from the BeanFactory/ApplicatioContext by invoking its getBean() method. Code sample will follow...
Is there a better way to do this? Only via configuration, hopefully? (Personally, I doubt there is...)
<bean id="protoBean" scope="prototype"
class="com.blahblah.ProtoBean" />
<bean id="singletonBean"
class="com.blahblah.SingletonBean" />
public class ProtoBean {
....
}
public class SingletonBean {
private BeanFactory factory;
public ProtoBean dispense() {
return (ProtoBean) factory.getBean("protoBean");
}
....
}
take a look at Method Injection
From Spring 3.0, we can use <aop:scoped-proxy> for dependency injection of the proper scope. Behind the scene, Spring injects proxied objects and is responsible for finding the right scope context, may it be prototype, session or request etc. See the official documentations here.
And to make life easier, Spring has also introduced proxyMode attribute for #Scope, so we are not limited to XML declarations only. For example:
#Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
Make sure to document clearly the injected bean is a proxy to warn others that getClass() and casting may not yield the expected result. Also, make sure equals() and hashCode() in the proxied class use access methods rather than directly accessing class variables.
Using method injection makes the singleton-bean class difficult to unit-test (you need to create a subclass to implement the method which gives out the dependency). Plus it's less reusable because you can't directly instantiate it, so if you're not using Spring and want to use this class, you'll need to subclass and provide the bean-returning method.
A better approach IMHO is to use a proxy, a prototype target source and a prototype target bean, as follows. Such a singleton-bean class is easily unit-testable and better reusable.
<bean id="targetPooledObject" class="pool.PooledObject" scope="prototype">
<constructor-arg value="42" />
</bean>
<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
<property name="targetBeanName" value="targetPooledObject" />
</bean>
<bean id="pooledObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="prototypeTargetSource" />
</bean>
<bean id="poolConsumer" class="pool.PoolConsumer">
<property name="pooledObject" ref="pooledObject" />
</bean>
Now we can inject pooledObject into a singleton bean (poolConsumer as shown above), and for every method call that we make on that singleton bean, (e.g. every time we call poolConsumer.callPooledObjectMethod() which in turn calls pooledObject.foo()) we get a new PooledObject bean.
Following is the corresponding code:
public class PooledObject
{
private int x;
public PooledObject(int x)
{
this.x = x;
}
public void foo()
{
System.out.println("foo called");
}
}
public class PoolConsumer
{
private PooledObject pooledObject;
public PooledObject getPooledObject()
{
return pooledObject;
}
public void setPooledObject(PooledObject pooledObject)
{
this.pooledObject = pooledObject;
}
public void callPooledObjectMethod()
{
pooledObject.foo();
}
}
I have two Spring proxies set up:
<bean id="simpleBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="simpleBeanTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>cacheInterceptor</value>
</list>
</property>
</bean>
<bean id="springDao" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="springDaoTarget"/>
<property name="interceptorNames">
<list>
<value>daoInterceptor</value>
</list>
</property>
</bean>
simpleBean works just fine -- springDao does not.
The SpringDao class looks like:
public class SpringDao extends JdbcDaoSupport {
private SimpleJdbcTemplate simpleJdbcTemplate;
public SimpleJdbcTemplate getSimpleJdbcTemplate() {
if (simpleJdbcTemplate==null) {
simpleJdbcTemplate= new SimpleJdbcTemplate(getDataSource());
}
return simpleJdbcTemplate;
}
...
And I have my unit test autowired like this:
#Autowired
#Qualifier("springDao")
protected SpringDao springDao;
And the first indication something is wrong is I get this error:
Could not autowire field: . . . nested
exception is
java.lang.IllegalArgumentException
If I comment out the #Qualifier annotation and run my unit test again, I get this:
No unique bean of type ... expected
single matching bean but found 2:
[springDaoTarget, springDao]
That is what I expected.
So I changed my autowiring to
#Autowired
#Qualifier("springDaoTarget")
protected SpringCustomerCapacityDao springDao;
And added the following to my unit test:
Object proxy = applicationContext.getBean("springDao");
Assert.assertNotNull(proxy);
Assert.assertTrue(proxy instanceof SpringDao);
And the instanceof test failed, which (to me) means that my proxy is not really my proxy.
So I'm confused. What's going on? How can I fix this?
Edit Here is the requested springDaoTarget definition, which will disappoint many people:
<bean id="springDaoTarget" class="com.company.SpringDao">
If the target of your proxy implements at least one interface then Spring's default behavior is to create a JDK Proxy that implements all the interfaces of the target. This means it will not be a subclass of the target class. You can override this by forcing the creation of CGLIB proxies instead which are dynamic subclasses of the target.
As a general rule, if you are going to use AOP but only use interfaces in a limited fashion you'll want to force CGLIB. Otherwise you will have lots of JDK Proxies in your container which are not of the same type as the bean implementations you loaded.
See Cliff Meyers blog: Spring AOP: CGLIB or JDK Dynamic Proxies?
It was easy to fix, once I figured it out. SpringDao no longer inherits from JdbcDaoSupport and now it works.