Spring AOP: Adding advice in a running application - spring

How can I add or remove Spring AOP proxies in a running application without restarting the server?
Something like this
GenericApplicationContext ctx = new GenericApplicationContext();
BeanDefinitionBuilder promotion4Advice = BeanDefinitionBuilder.rootBeanDefinition(Promotion4Action.class).addPropertyValue("discountPercentage", 0.5);
promotion4Advice.addPropertyValue("discountCode", 16);
promotion4Advice.addPropertyValue("discountComment", "50% on regular item");
ctx.registerBeanDefinition("promotion4Advice", promotion4Advice.getBeanDefinition());
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ProxyFactoryBean.class);
builder.addPropertyValue("proxyTargetClass", true);
builder.addPropertyValue("interceptorNames", new String[] {"promotion4Advice"});
ctx.registerBeanDefinition("proxyFactoryBean", builder.getBeanDefinition());
My XML config looks like this:
<bean id="promotion4Advice"
class="com.promotion.actions.Promotion4Action">
<property name="discountPercentage" value="0.5" />
<property name="discountCode" value="16" />
<property name="discountComment" value="50% on regular item" />
</bean>
<aop:config proxy-target-class="true">
<aop:aspect id="promotion4Aspect" ref="promotion4Advice">
<aop:pointcut id="promotion4PointCut"
expression="execution(* com.controller.ShoppingBagController.defaultHandler(javax.servlet.http.HttpServletRequest)) and args(request)" />
<aop:before pointcut-ref="promotion4PointCut" method="applyPromotion4"
arg-names="request" />
</aop:aspect>
<aop:aspect id="promotion4Aspect1" ref="promotion4Advice">
<aop:pointcut id="promotion4PointCut1"
expression="execution(* com.controller.ReviewOrderController.handleRequest(javax.servlet.http.HttpServletRequest)) and args(request)" />
<aop:before pointcut-ref="promotion4PointCut1" method="interceptOrderDetails"
arg-names="request" />
</aop:aspect>
<aop:aspect id="promotion4Aspect4" ref="promotion4Advice">
<aop:pointcut id="promotion4PointCut4"
expression="execution(* com.controller.ShoppingBagController.applyPromoCode(javax.servlet.http.HttpServletRequest, String, String)) and args(request, promoCode, mappedURL)" />
<aop:after pointcut-ref="promotion4PointCut4" method="interceptPromoCode"
arg-names="request,promoCode,mappedURL" />
</aop:aspect>
</aop:config>
This is one of the promotions... Like the above i have 3 other and want to be able to configure these dynamically through aop without changing the xml and restarting the server. Please help

I don't think you can, mainly because Spring wires beans during context startup. This means if bean A is injected into bean B and the former one is not wrapper with any proxy, it will be injected directly.
Now of course you can take A, wrap it in a proxy and put it back in the container (as a copy A'). But B does not know about A' at all.
If your know in advance which beans are subject to dynamic adding/removing aspects, wrap them eagerly in aspect that does nothing on startup (e.g. calling sort of NoOpStrategy). When you need to "add" the aspect, just change that strategy to something else.

Related

Spring AOP : Logging function not getting called via aspectJ, have attached the xml file below

Below is the XML file not sure why the function creditCardAmountBorrowedUpdation() is not getting called:
<aop:config>
<aop:aspect id="beforeTransactions" ref="authorizeCCTransactionsLogs">
<aop:pointcut
expression="execution(void AuthorizeCCTransactions.CreditCardHelper.creditCardAmountBorrowedUpdation(..))"
id="beforeDepositing"/>
<aop:before method="beforeApprovingCCTransactions" pointcut-ref="beforeDepositing"/>
<aop:after method="afterApprovingCCTransactions" pointcut-ref="beforeDepositing"/>
</aop:aspect>
</aop:config>

Spring DI : session vise object creation using aop proxy for inherited class

In my project i have used struts2 and spring. Spring is used just for DI. I am having all my actions created by sessions and so as model beans via spring DI. Now I want to use inheritance for my class which will be generated through aop based proxy and it will be per session. Coding goes as below.
<bean id="common.EshopDefaultAction" class="com.common.actions.EshopDefaultAction" scope="session" >
<property name="site" ref="master.site" />
<property name="menu" ref="master.menu" />
<property name="indexDAO" ref="common.indexDAO" />
<property name="categoryDAO" ref="master.categoryDAO" />
<property name="productDAO" ref="master.productDAO" />
</bean>
<bean id="common.IndexAction" parent="common.EshopDefaultAction" class="com.common.actions.IndexAction" scope="session">
<property name="indexInfo" ref="common.indexInfo" />
<aop:scoped-proxy />
</bean>
both actions are having pairs of setters and getters.
I want to have site,menu, indexDAO, categoryDAO, productDAO objects created by session for all of its child like IndexAction just shown above. Right now it creates different objects for EshopDefaultAction and IndexAction.
Adding <aop:scoped-proxy /> to EshopDefaultAction bean definition gives error like
Invalid property 'targetBeanName' of bean class [com.common.actions.IndexAction]:
Bean property 'targetBeanName' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?

getting new bean instances of referencing beans every time

I have two queries ...
1) I have a query that beans are intialized in the spring container itself when the spring container is intialiazed and before the call is made to the get bean() method , this is the default behavior , how can I configure the application in such way that bean should be initalized in container only when a call is made of getbean() is made, shall we declare the bean as prototype to achieve this.
2) second query is that first please go through the below example first...
<beans>
<bean id="triangle" class="Demo.Triangle" scope="singleton" >
<property name="pointA" ref="zeropoint"/>
<property name="pointB" ref="firstpoint"/>
<property name="pointC" ref="secondpoint"/>
</bean>
<bean id="zeropoint" class="Demo.Point" scope="prototype" >
<property name="x" value="10" />
<property name="y" value="20" />
</bean>
<bean id="firstpoint" class="Demo.Point" scope="prototype" >
<property name="x" value="10" />
<property name="y" value="20" />
</bean>
<bean id="secondpoint" class="Demo.Point" scope="prototype">
<property name="x" value="10" />
<property name="y" value="20" />
</bean>
As indicated above that triangle bean is singleton and it references bean are protoype now when I access singleton the other refernces beans zeropoint,firstpoint and secondpoint are also initaizes only once with respect to triangle but Here I want that every time new instance of these three beans to be get created when the triangle bean is fetched , Please advise how that is achieable. is it achievable through my pojo implementing ApplicationContextAware interface, Please advise
Instead of relying on Spring infrastructure (BeanFactoryAware) I recommend trying lookup method feature:
abstract class Triangle {
public abstract Point createZeroPoint();
public abstract Point createFirstPoint();
public abstract Point createSecondPoint();
public void foo() {
Point p0 = createZeroPoint();
Point p1 = createFirstPoint();
Point p2 = createSecondPoint();
}
}
Every time you call create*Point() abstract method, it creates new instance of Point. But how do you implement this method and how does it know which bean to return? Spring implements this for you!
<bean id="triangle" class="Demo.Triangle" scope="singleton">
<lookup-method name="createZeroPoint" bean="zeropoint"/>
<lookup-method name="createFirstPoint" bean="firstpoint"/>
<lookup-method name="createSecondPoint" bean="secondpoint"/>
</bean>
Check out the comprehensive documentation: 4.4.6.1 Lookup method injection.
Its called Lazy loading
<bean id="myBean" class="a.b.MyBean" lazy-init="true"/>
First note that your firstpoint and secondpoint beans don't have a valid scope definition (you missed the scope=)
Prototype scope means that every bean that requires a prototype bean gets its own instance. If would define multiple triangles which all have a dependency to zeropoint every triangle would a separate zeropoint instance.
If you need new point instances inside your triangle class (e.g. every time you call a method of triangle) the best way is to receive instances directly from the bean factory:
E.g.
class MyClass implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void doSomethingThatRequiresNewInstance() {
Triangle t = beanFactory.getBean("zeropoint", Triangle.class);
// because zeropoint is defined as prototype you get a new instance everytime you call getBean(..)
}
}

Is there a better way to Configure Bean?

Can the following Spring DI xml be improved? Below the xml is the programmatic approach of configuring the target bean.
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" />
<bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="jacksonSerializationConfig" />
<property name="targetMethod" value="setSerializationInclusion" />
<property name="arguments">
<list>
<value type="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion">NON_NULL</value>
</list>
</property>
</bean>
ObjectMapper mapper = new
ObjectMapper();
mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
XML is a really bad way of doing this. Yes, you can do this, but it's much easier to write a FactoryBean which configures your ObjectMapper:
public class MyObjectMapperFactoryBean extends AbstractFactoryBean<ObjectMapper> {
public Class<ObjectMapper> getObjectType() {
return ObjectMapper.class;
}
public ObjectMapper createInstance() {
// create and return ObjectMapper
}
}
and then in your XML:
<bean id="jacksonObjectMapper" class="x.y.MyObjectMapperFactoryBean" />
Still not totally ideal, but a little cleaner:
<bean id="objectMapperBuilder1" class="org.codehaus.jackson.map.ObjectMapper"/>
<bean id="objectMapperBuilder2" factory-bean="objectMapperBuilder1" factory-method="setSerializationInclusion">
<constructor-arg value="NON_NULL"/>
</bean>
<bean id="jsonWriter" factory-bean="objectMapperBuilder2" factory-method="writerWithDefaultPrettyPrinter" />
<!-- etc, etc -->
One downside is that you'll have unnecessary bean instances in memory. (I'm using this method, and I'll live with it until Spring decides to handle these). There are many threads here and on the Spring forums asking for support with fluent setters like the builder pattern used by Jackson, but until then you have to choose the lesser evil for you.
I agree with #skaffman's general approach of using a FactoryBean in place of the unavoidably convoluted Spring XML bean configuration to configure a Jackson ObjectMapper. Spring 3.2+ now provides such a FactoryBean out of the box. See JacksonObjectMapperFactoryBean / Jackson2ObjectMapperFactoryBean. Here's an example of the Spring XML to configure the ObjectMapper via the Spring FactoryBean -
<bean id="jacksonObjectMapper" factory-bean="&jacksonObjectMapperFactoryBean" factory-method="getObject"/>
<bean id="jacksonObjectMapperFactoryBean" class="org.springframework.http.converter.json.JacksonObjectMapperFactoryBean">
<property name="featuresToDisable">
<array>
<util:constant static-field="org.codehaus.jackson.map.SerializationConfig$Feature.WRITE_NULL_PROPERTIES"/>
</array>
</property>
</bean>
(Note the need to use &amp in the 'factory-bean' attribute to instruct Spring to use the factory method on the FactoryBean itself, rather than the bean it creates).

How to use Dynamic Proxies with JSF when the method signature contains Object ... args

I'm having some trouble with Spring, JPA and Dynamic Proxy DAO classes which are initialized as Spring Beans. This particular project has been plaguing me on the persistence/transaction side for some time, and I'd like to get this nailed down once and for all.
First, here's a method from the DAO interface:
/**
* Perform a named query using numbered parameters and return the results as a list
* #param name
* #param params
* #return query results
*/
List getNQasList(String name, Object... params);
This bean is registered automatically with Spring using a postProcessBeanFactory method:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
this.beanFactory = beanFactory;
for (Class entityClass : this.getPersistedClassList()) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
ConstructorArgumentValues constructorVals = new ConstructorArgumentValues();
constructorVals.addIndexedArgumentValue(0, entityClass);
beanDefinition.setConstructorArgumentValues(constructorVals);
beanDefinition.setBeanClass(GenericDAOImpl.class);
beanDefinition.setAutowireCandidate(true);
beanDefinition.setLazyInit(true);
beanDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
String simpleName = entityClass.getSimpleName();
String convertedName = "" + simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1) + "Dao";
registry.registerBeanDefinition(convertedName, beanDefinition);
}
}
The method getPersistedClassList() reads persistence.xml and finds all of the JPA classes. The above method registers each of these instances with Spring so they can be accessed easily by the variable "entityNameDao". Because this class is a transactional class, it gets initialized as a Dynamic Java Proxy, and that's where my problems begin. JSF doesn't perceive the object by its interfaces anymore, but looks directly at the proxy, which does in fact show the above method definition as:
List getNQasList(String name, Object[] params);
This makes it much more difficult to access from JSF than an Object... params signature method. Is there any way I can get JSF to recognize these objects by their interface, or convince Spring to somehow not make dynamic proxies of them? Alternatively, how does one go about doing the following in EL, it gives me errors about the curly braces if I try:
new Object[] {...}
My spring config relating to persistence, including the transaction advice is included below for good measure.
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="${JDBC_CONNECTION_STRING}?autoReconnect=true&useUnicode=true&connectionCollation=utf8_general_ci&characterSetResults=utf8"/>
<property name="username" value="${PARAM1}"/>
<property name="password" value="${PARAM2}"/>
<property name="validationQuery" value="select 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<context:annotation-config/>
<!-- Enable aspectj based transactions -->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />
<!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the GenericDAOImpl class -->
<aop:config>
<aop:pointcut id="DaoOps" expression="execution(* daos.GenericDAOImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="DaoOps"/>
</aop:config>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
<property name="showSql" value="true"/>
</bean>
</property>
</bean>

Resources