My code:-
<context:annotation-config/>
<bean id="arthmeticCalculator" class="com.manoj.aop.test.CalculatorImpl" lazy-init="true"/>
<bean id="stubCalculator" class="com.manoj.aop.test.StubCalculator" lazy-init="true"/>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Calculator</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>methodNameAdvisor</value>
</list>
</property>
</bean>
<bean id="methodNameAdvisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedNames">
<list>
<value>add</value>
<value>sub</value>
</list>
</property>
<property name="advice" ref="loggingAroundAdvice" />
</bean>
<bean id="loggingAroundAdvice" class="com.manoj.aop.test.LoggingAroundAdvice">
<constructor-arg><ref bean="arthmeticCalculator"/></constructor-arg>
<constructor-arg><ref bean="stubCalculator"/></constructor-arg>
<constructor-arg><value>false</value></constructor-arg>
</bean>
<bean id="testService" class="com.manoj.aop.test.TestService">
<!--
<property name="arthmeticCalculator" ref="arthmeticCalculator"/>
-->
</bean>
Java Code:
package com.manoj.aop.test;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
public class LoggingAroundAdvice implements MethodInterceptor{
Calculator actualCalculator;
Calculator stubCalculator;
boolean useStub;
public LoggingAroundAdvice(Calculator actualCalculator, Calculator stubCalculator, boolean useStub) {
this.actualCalculator = actualCalculator;
this.stubCalculator = stubCalculator;
this.useStub = useStub;
}
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Around Invoice called");
Calculator calc = useStub ? stubCalculator: actualCalculator;
System.out.println(calc.getClass().getName());
Object result = methodInvocation.getMethod().invoke(calc, methodInvocation.getArguments());
return result;
}
}
import org.springframework.beans.factory.annotation.Autowired;
public class TestService {
#Autowired
private Calculator arthmeticCalculator;
public void test(){
System.out.println(arthmeticCalculator.getClass().getName());
System.out.println(arthmeticCalculator.add(5, 10.5));
}
}
Sorry guys I dont know how to format text in this editor,
My problem is :-
Spring is creating proxy for the class but never execute the Invoke method of the Around advice. Can some body please tell me whats going on and how to make it call the invoke method?
Here is the output of test class:-
$Proxy4
15.5
Thanks ,
Manoj
Which version of Spring are you using? The way you are doing proxy is the older way. The better way is to use the annotation or pure POJO+XML way. You can check a short introduction on AOP section here
Related
I have a list of strings, that i would like to define in beans.xml.
<util:list id="myFractions" value-type="java.lang.String">
<value>#{ T(com.myapp.longname.verylong.WelcomeController).RED_FRACTION }</value>
<value>#{ T(com.myapp.longname.verylong.WelcomeController).BLUE_FRACTION }</value>
<value>#{ T(${my.prefix}).GREEN_FRACTION }</value>
</util:list>
It works fine, but each time I need to write the full qualified constant's name com.myapp.longname.verylong.WelcomeController. I would like to write it only once. One solution I have found is to replace it with a property like my.prefix so I can write only my short prefix instead of the real full path. But then I will need to pollute the global "namespace" with property that is only needed once. I would like to define a placeholder only for this list or at least only for this beans.xml file. I have already tried to define a property directly in beans.xml with PropertyPlaceholderConfigurer and it works, but then all my inital properties are not available anymore.
So how can I avoid to writing com.myapp.longname.verylong.WelcomeController each time in a list as a prefix and only define it once? Ideally something like
<util:list id="myFractions" value-type="java.lang.String">
<define-local-placeholder name="my.prefix" value="com.myapp.longname.verylong.WelcomeController" />
<value>#{ T(${my.prefix}).RED_FRACTION }</value>
<value>#{ T(${my.prefix}).BLUE_FRACTION }</value>
<value>#{ T(${my.prefix}).GREEN_FRACTION }</value>
</util:list>
Please give a try on this
<context:property-placeholder properties-ref="shorthandHelperConstants"/>
<util:properties id="shorthandHelperConstants">
<prop key="my.prefix">com.myapp.longname.verylong.WelcomeController</prop>
</util:properties>
<util:list id="myFractions" value-type="java.lang.String">
<value>#{ T(${shorthandHelperConstants['my.prefix']}).RED_FRACTION }</value>
<value>#{ T(${shorthandHelperConstants['my.prefix']}).BLUE_FRACTION }</value>
<value>#{ T(${shorthandHelperConstants['my.prefix']}).GREEN_FRACTION }</value>
</util:list>
Try defining your prefix in properties file and use it in your beans.xml as shown here:
Best ways to deal with properties values in XML file in Spring, Maven and Eclipses
and here
Using Variable Substitution from Configuration Files in Spring
Another solution is using SpEL
<property name="userCountry" value="#{'India'}" />
Spring Expression Language (SpEL) Example
Checkout out Constants. Which allows you to extract constants and values from classes, this way you only need to define your class onetime instead for each property.
<bean id="someConstants" class="org.springframework.core.Constants">
<constructor-arg value="your-class-name=here" />
</bean>
<bean id="myFractions" factory-bean="someConstants" factory-method="getValuesForSuffix">
<constructor-arg value="FRACTION" />
</bean>
This will expose all of your constants which end with FRACTION as a Set in your context. Without you needing to define each and every constant. You could also place this into a FactoryBean making it a little easier
public class FractionExporter extends AbstractFactoryBean<List<String>> {
#Override
public Class<List> getObjectType() {
return List.class;
}
protected List<String> createInstance() {
Constants constants = new Constants(YourClass.class);
return new ArrayList(constants.getValuesForSuffix("FRACTION"));
}
}
You could now define this FactoryBean in XML
<bean id="myFractions" class="FractionExporter" />
A solution is to implement a FactoryBean,
by extending the AbstractFactoryBean class:
package test;
import java.util.*;
import org.springframework.beans.factory.config.AbstractFactoryBean;
public class ConstantListFactoryBean extends AbstractFactoryBean<List<Object>>
{
private Class<?> targetClass;
private List<String> constantNames;
public void setTargetClass(Class<?> targetClass)
{
this.targetClass = targetClass;
}
public void setConstantNames(List<String> constantNames)
{
this.constantNames = constantNames;
}
#Override
public Class<List> getObjectType()
{
return List.class;
}
#Override
protected List<Object> createInstance() throws Exception
{
ArrayList<Object> list = new ArrayList<Object>();
for(String name : constantNames)
list.add(targetClass.getField(name).get(null));
return list;
}
}
Here is a sample beans.xml that uses the ConstantListFactoryBean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="colors" class="test.ConstantListFactoryBean">
<property name="targetClass" value="test.Colors"/>
<property name="constantNames">
<list>
<value>RED</value>
<value>BLUE</value>
<value>GREEN</value>
</list>
</property>
</bean>
</beans>
And the sample class that holds the constants:
package test;
public class Colors
{
public static final String RED = "red";
public static final String BLUE = "blue";
public static final String GREEN = "green";
}
And finally, some code that shows that it works:
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
List colors = (List)context.getBean("colors");
System.out.println(colors);
}
}
Output:
[red, blue, green]
Another simpler way is to create an object that wrap a class instance (e.g call ClassReflector). Then define a method on it to return the value of the constant field.
For example :
import org.springframework.util.ReflectionUtils;
public class ClassReflector {
private Class<?> clazz;
public ClassReflector(String className) throws Exception {
this.clazz = Class.forName(className);
}
public String getFieldVal(String fieldName) throws Exception {
return (String) ReflectionUtils.getField(clazz.getField(fieldName), null);
}
}
Then in the XML, use this method to get the value of different constant fields.
<bean id="cf" class="com.myapp.longname.verylong.ClassReflector">
<constructor-arg value="com.myapp.longname.verylong.WelcomeController" />
</bean>
<util:list id="myFractions" value-type="java.lang.String">
<value>#{cf.getFieldVal('RED_FRACTION')}</value>
<value>#{cf.getFieldVal('BLUE_FRACTION')}</value>
<value>#{cf.getFieldVal('GREEN_FRACTION')}</value>
</util:list>
As per comments & question, as your requirement is quite minimal , I would define one general purpose map & put key-value there & then access it inside your list:
<bean id="map" class="java.util.HashMap">
<constructor-arg>
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="my.prefix" value="com.myapp.longname.verylong.WelcomeController" />
</map>
</constructor-arg>
</bean>
<util:list id="myFractions" value-type="java.lang.String">
<value>#{ T(${map['my.prefix']}).RED_FRACTION }</value>
<value>#{ T(${map['my.prefix']}).BLUE_FRACTION }</value>
<value>#{ T(${map['my.prefix']}).GREEN_FRACTION }</value>
</util:list>
Benefit I can see here is you can put as many key-values in this map if you have multiple prefixes / properties of this kind & you want to access it in different beans without defining any global scoped beans.
Please let me know if this is of any help.
I'm trying to move from a xml based config to java annotations
I need your help getting this to work:
Obviously I can't set the RemoteJco interface to my SapConnector but what can I do to get this xml-config working?
#Bean
public RmiProxyFactoryBean jcoPool(){
RmiProxyFactoryBean jcoPool = new RmiProxyFactoryBean();
jcoPool.setServiceUrl("rmi://localhost/CH");
jcoPool.setServiceInterface(RemoteJco.class);
jcoPool.setRefreshStubOnConnectFailure(true);
return jcoPool;
}
#Bean
public SapConnector SapConnector(){
SapConnector sapConnector = new SapConnector();
sapConnector.setJcoPool(jcoPool());
return sapConnector;
}
this in the XML-Config works just fine:
<!-- JCO-Pool RMI Service -->
<bean id="jcoPool" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost/CH"/>
<property name="serviceInterface" value="com.itensis.jco.common.RemoteJco"/>
<property name="refreshStubOnConnectFailure" value="true" />
</bean>
<bean id="SapConnector" class="com.itensis.core.SapConnector">
<property name="jcoPool">
<ref bean="jcoPool" />
</property>
</bean>
this is my SAP-Connector
#Service
public class SapConnector {
#Autowired private RemoteJco jcoPool;
public RemoteJco getJcoPool() {
return jcoPool;
}
public void setJcoPool(RemoteJco jcoPool) {
this.jcoPool = jcoPool;
}
}
You have to make some changes on the jcoPool bean:
#Bean
public RemoteJco jcoPool(){
RmiProxyFactoryBean jcoPool = new RmiProxyFactoryBean();
jcoPool.setServiceUrl("rmi://localhost/CH");
jcoPool.setServiceInterface(RemoteJco.class);
jcoPool.setRefreshStubOnConnectFailure(true);
jcoPool.afterPropertiesSet();
return (RemoteJco) jcoPool.getObject();
}
Make sure that you return value has the same class as you used as service interface. And you have to call afterPropertiesSet() before calling getObject on the RmiProxyFacotoryBean instance.
Is it possible to invoke static method in Spring configuration file?
public MyClass {
public static void staticMethod() {
//do something
}
}
<bean id="myBean" class="MyClass">
<!-- invoke here -->
</bean>
When the static method creates an instance of MyClass you an do it like this
config
<bean id="myBean" class="MyClass" factory-method="staticMethod">
<!-- invoke here -->
</bean>
code
public static MyClass staticMethod() {
//create and Configure a new Instance
}
If you want the method only to be called on bean instantiation spring can't do it this way.
config
<bean id="myBean" class="MyClass" init-method="init">
<!-- invoke here -->
</bean>
code
public static void staticMethod() {
//create and Configure a new Instance
}
public void init() {
staticMethod();
}
try this
<bean id="b1" class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="staticMethod" value="MyClass.staticMethod" />
</bean>
see http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/MethodInvokingBean.html
Try something like this:
<!-- call static method -->
<bean id="test" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="MyClass" />
<property name="targetMethod" value="staticMethod" />
<property name="arguments">
<list>
<value>anArgument</value>
</list>
</property>
</bean>
Remove arguments as you might not need them.
Taken from https://gist.github.com/bulain/1139874
I was needing to call a static method. The above code worked fine.
This might be useful as well: How to make spring inject value into a static field.
If you are using annotations for spring configuration you can add the following method into your #Configuration class:
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod("MyClass.staticMethod");
return methodInvokingFactoryBean;
}
I've a class which takes in 2 Object Injections. 1 of them is to be injected through other bean ref whereas the other injected based on bean call. I want to instantiate an object using spring. How can I do this ?
I tried doing this:
MyBean Class:
class MyBean{
Injection1 ijn1;
MyBean(Injection1 ijn1,Injection2 ijn2){
this.ijn1=ijn1;
this.ijn2=ijn2;
}
}
Beans.xml
<bean name="myBean" class="MyBean" scope="prototype">
<constructor-arg>
<null />
</constructor-arg>
<constructor-arg>
<ref bean="injection2" />
</constructor-arg>
</bean>
<bean name="injection2" class="Injection2">
</bean>
Application Code:
MyBean getMyBean(Injection ijn1) {
return (MyBean)context.getBean("myBean", new Object[] { ijn1 })
}
But this doesn't works.
Any tips ?
You code doesn't work because spring looks for a MyBean's constructor like MyBean(Injection1 ijn1); you have to pass injection2 in this way.
MyBean getMyBean(Injection ijn1) {
return (MyBean)context.getBean("myBean", new Object[] { ijn1, context.getBean("injection2") })
}
If you want to use your code another way is to have partial inject in this way:
class MyBean{
Injection1 ijn1;
Injection2 ijn2;
MyBean(Injection1 ijn1){
this.ijn1=ijn1;
}
public void setIjn2(Injection2 ijn2I ) {
this.ijn2 = ijn2;
}
}
and in xml
<bean name="myBean" class="MyBean" scope="prototype">
<property name="inj2" ref="injection2" />
</bean>
<bean name="injection2" class="Injection2">
</bean>
I need help making AOP work. What am I missing here?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="duke" class="com.tutorial.springidol.Singer">
<constructor-arg value="Duke"/>
<constructor-arg>
<bean class="com.tutorial.springidol.Song">
<property name="title" value="ABC"/>
</bean>
</constructor-arg>
</bean>
<bean id="audienceAdvice" class="com.tutorial.advice.AudienceAdvice">
<property name="audience">
<bean class="com.tutorial.springidol.Audience"/>
</property>
</bean>
<bean id="audienceAdvisor"
class="org.springframework.
aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="audienceAdvice"/>
<property name="pattern" value=".*perform"/>
</bean>
</beans>
AudienceAdvice.java
public class AudienceAdvice implements MethodBeforeAdvice,
AfterReturningAdvice {
#Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
audience.takeSeats();
audience.turnOffCellphones();
}
#Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
audience.applaud();
}
private Audience audience;
public void setAudience(Audience audience) {
this.audience = audience;
}
}
The AOP does not work but the target executes though.
You've declared the target bean and the advice, but by default Spring doesn't know to actually apply the advice to the target.
You need to run an Autoproxy.
One way to do this:
<!-- Autoproxy -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>duke</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>audienceAdvisor</value>
</list>
</property>
</bean>