Spring AOP : Can we access bean object by getBean("beanName") method after applying ProxyFactoryBean on that Bean? - maven

I have applied a 'BeforeAdvice' through 'ProxyFactoryBean' on a Bean of type "MyXMLApplication" now I am not able to access the Bean object directly{by getBean(MyXMLApplication.class)}, it is giving error :-
by setter dependency injection myxml
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.di.consumer.MyXMLApplication] is defined: expected single matching bean but found 2: MyXMLApp,proxy
However I am able to get the bean object by "proxy" bean object{(MyXMLApplication)context.getBean("proxy")}. Now my question is after applying proxy on any bean is there any way to access it directly without proxy bean.
My code is:
********Before Advisor*********
public class MyBeforeAdvisor implements MethodBeforeAdvice{
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
// TODO Auto-generated method stub
System.out.println("before advice run");
}
}
*********applicationContext.xml********
<bean id="twitter" class="com.journaldev.spring.di.services.TwitterService"></bean>
<bean id="MyXMLApp" class="com.journaldev.spring.di.consumer.MyXMLApplication" autowire="byType"/>
<bean id="beforeAdvice" class="com.journaldev.spring.aop.advisor.MyBeforeAdvisor"></bean>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="MyXMLApp"></property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
</list>
</property>
</bean>
**********Main Bean Class************
public class MyXMLApplication {
private MessageService service;
public void setService(MessageService svc){
System.out.println("by setter dependency injection myxml");
this.service=svc;
}
public boolean processMessage(String msg, String rec) {
return this.service.sendMessage(msg, rec);
}
}
**********Autowired Bean Interface *******
public interface MessageService {
boolean sendMessage(String msg, String rec);
}
**********Autowired Bean Impl*********
public class TwitterService implements MessageService {
public boolean sendMessage(String msg, String rec) {
System.out.println("Twitter message Sent to "+rec+ " with Message="+msg);
return true;
}
}
************* Main function**********
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MyXMLApplication app = context.getBean(MyXMLApplication.class); --> Not Working
//MyXMLApplication app = (MyXMLApplication)context.getBean("proxy"); -->working
app.processMessage("Hi", "abc#abc.com");
context.close();
}

Sorry guys, the error was coming because I was calling getBean(MyXMLApplication.class) [by type] that is why it founds two beans "proxy" and "MyXMLApp" of type MyXMLApplication.class and giving the error.
It is not something like we can not call the 'getBean'method on bean directly after applying any proxy on that.

Related

How to Instantiate spring bean with in a method with runtime constructor arguments?

I need to instantiate a bean ( EmployeeSaver) with in a method with parameter coming in dynamically. I can't use constructor setter for these values are not populated at config time.
Sample code:
class MyEmployeeBean{
public void saveEmployeeDetail (Employee employee , EmployeeHistory hist ){
EmployeeDetail detail = hist.getDetail();
EmployeeSaver eSave = new EmployeeSaver(employee, detail)
saver.saveEmployee();
}
}
class EmployeeSaver {
private Employee empl;
private EmployeeDetail detail;
public EmployeeSaver(Employee emp, EmployeeDetail det){
empl = emp;
detail = det;
}
public void saveEmployee(){
// code to same the guy...
}
}
As MyEmployeeSaver class don't have default constructor so it's throwing runtime exception. I am unsable to use following config as employeeDetail is not know until I do hist.getDetail() !
<bean id="mySaverBean" class="come.saver.EmployeeSaver">
<constructor-arg name="empl" ref="employee" />
<constructor-arg name="hist" ref = "employeeHistory" />
</bean>
How to instantiate employeeSaverBean with constructor arguments?
You can't do this directly with Spring configuration, but using ApplicationContext.getBean(String beanName,Object...args) like described in this question.
MyEmployeeBean must implements ApplicationContextAware to access Spring's context
class MyEmployeeBean implements ApplicationContextAware {
ApplicationContext applicationContext;
void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void saveEmployeeDetail (Employee employee , EmployeeHistory hist ){
EmployeeDetail detail = hist.getDetail();
EmployeeSaver eSave = (EmployeeSaver)this.applicationContextnew.getBean("mySaverBean", employee, detail);
saver.saveEmployee();
}
}
and in beans.xml
<bean id="mySaverBean" class="come.saver.EmployeeSaver" scope="prototype" />
Remeber to addo scope="prototype" to let Spring create a new instance at every request.

Accessing spring bean from logging appender class

I have log4j DailyRollingFileAppender class in which setFile() method I need to check database value to decide which file to used for logging.
DailyRollingFileAppender class
public void setFileName()
{
isLoginEnabled = authenticationManager.checkLoginLogging();
}
Here 'authenticationManager' is object of class used to make database call using spring dependency injection feature.
spring-beans.xml
<bean id="dailyRollingFileAppender" class="com.common.util.DailyRollingFileAppender">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
</bean>
<bean id="authenticationManager" class="com.security.impl.AuthenticationManagerImpl">
<property name="userService">
<ref bean="userService"/>
</property>
</bean>
Now when I start my application log4j gets initiated first and since spring-beans is yet to invoked it throws NullPointerException in method setFileName().
So is there a way I can make call to 'authenticationManager.checkLoginLogging();' from DailyFileAppender class so that when log4j loads it should able to get database value?
A few years late, but I hope this is of help to someone.
I was after similar functionality - I have a custom appender, and i wanted to use an autowired bean to perform some logging using a service we'd built. By making the appender implement the ApplicationContextAware interface, and making the field that i'd normally autowire static, i'm able to inject the spring-controlled bean into the instance of the appender that log4j has instantiated.
#Component
public class SslErrorSecurityAppender extends AppenderSkeleton implements ApplicationContextAware {
private static SecurityLogger securityLogger;
#Override
protected void append(LoggingEvent event) {
securityLogger.log(new SslExceptionSecurityEvent(SecurityEventType.AUTHENTICATION_FAILED, event.getThrowableInformation().getThrowable(), "Unexpected SSL error"));
}
#Override
public boolean requiresLayout() {
return false;
}
#Override
public synchronized void close() {
this.closed = true;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext.getAutowireCapableBeanFactory().getBean("securityLogger") != null) {
securityLogger = (SecurityLogger) applicationContext.getAutowireCapableBeanFactory().getBean("securityLogger");
}
}
}

Why do the protected fields of type String not get Autowired, while other beans do

I am trying to set value of protected String field in a annotation configured bean using property-override mechanism. It throws following exception unless I add a setter for the field in the bean.
org.springframework.beans.NotWritablePropertyException: Invalid property 'cookie' of bean class [com.test.TestBean]: Bean property 'cookie' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
To compare I also have another protected field which is of type of another class. Bean of the other class is defined in XML. This field gets properly autowired.
Here's the first bean
#Component("testBean")
public class TestBean {
protected #Autowired(required=false) String cookie;
protected #Autowired InnerBean innerBean;
public String getCookie() {
return cookie;
}
public void setCookie(String cookie) {
this.cookie = cookie;
}
public InnerBean getInnerBean() {
return innerBean;
}
}
Here's InnerBean
public class InnerBean {
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
Spring configuration file - only interesting bits
<context:property-override location="beans.properties"/>
<context:component-scan base-package="com.test"></context:component-scan>
<context:annotation-config></context:annotation-config>
<bean id="innerBean" class="com.test.InnerBean">
<property name="value">
<value>Inner bean</value>
</property>
</bean>
beans.properties
testBean.cookie=Hello Injected World
Main
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
TestBean bean = context.getBean(TestBean.class);
System.out.println("Cookie : " + bean.getCookie());
System.out.println("Inner bean value : " + bean.getInnerBean().getValue());
}
Output
Cookie : Hello Injected World
Inner bean value : Inner bean
If I just comment out the setter for cookie in TestBean, I get the mentioned NotWritablePropertyException exception. Is there a difference between autowiring a bean and autowiring a property?
#Autowired should only be used when you want to wire up a Spring bean to another bean.
Properties are set by PropertyOverrideConfigurer which is a different process to autowiring, and doesn't use the #Autowired annotation. That #Autowired annotation on the cookie property is unnecessary and probably confusing Spring's bean factory. I expect that simply removing the annotation should fix the problem for you, ie:
protected String cookie;
protected #Autowired InnerBean innerBean;
Spring is capable of setting properties even if they are private or protected.

Enabling AOP breaks my dependency injection for a factory bean that takes a string

Enabling AOP breaks my dependency injection for a factory bean that takes a string.
Here's the fragment from the context file:
<aop:aspectj-autoproxy/>
<bean id="foo"
class="FooFactory"
p:url-ref="url"/>
<bean id="url" class="java.lang.String">
<constructor-arg value="#{ 'localhost:50131'}"/>
</bean>
Here's the factory bean.
public class FooFactory extends AbstractFactoryBean<Foo> {
private String url;
public void setUrl(final String url) {
this.url = url;
}
#Override
public Class<?> getObjectType() {
return Foo.class;
}
#Override
protected Foo createInstance() throws Exception {
Validate.notNull(url, "null URL");
return new FooFactory().createFoo(new String[]{url});
}
}
Here is the only declared aspect:
#Component
#Aspect
public class ProfilerAspect {
#Around("#target(org.springframework.stereotype.Controller) && args(model,..)")
public Object profileController(final ProceedingJoinPoint proceedingJoinPoint, final Model model) throws Throwable {
return proceedingJoinPoint.proceed();
}
}
And this is the exception
java.lang.IllegalStateException: Cannot convert value of type [$Proxy13 implementing java.io.Serializable,java.lang.Comparable,java.lang.CharSequence,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [java.lang.String] for property 'url': no matching editors or conversion strategy found
It seems, that it has to do with the #target designator in the pointcut expression. I can reproduce the behaviour with a simple setup similar to yours (with only a custom annotation in the pointcut). It works fine with a simple execution() designator though.
Unfortunatly, I have no idea why this causes Spring to proxy the String object.
<aop:aspectj-autoproxy/> doesn't perform proxying without a reason. Perhaps you declared some aspect whose pointcut includes Strings, therefore it have been proxied.

Problem instantiating generic class bean in Spring

I'm trying to instantiate a generic class in Spring, but I get following exception:
Initialization of bean failed; nested exception is
org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class football.dao.jpa.GenericJpaDAO]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given:
This is the XML configuration for Spring container:
<bean id="clubDAO" class="football.dao.jpa.GenericJpaDAO">
<constructor-arg type="EntityManagerFactory" ref="entityManagerFactory"/>
<constructor-arg type="Class" value="football.model.entities.ClubEntity"/>
<constructor-arg type="String" value="ClubEntity"/>
</bean>
This is the generic class:
public class GenericJpaDAO <T extends HavingID> {
private EntityManager em;
private Class entityClass;
private String entityName;
public GenericJpaDAO( Class entityClass, String entityName,
EntityManagerFactory emFactory ) {
this.entityClass = entityClass;
this.entityName = entityName;
em = emFactory.createEntityManager();
}
#Transactional
public void create( T entity ) {
em.persist( entity );
}
// more methods
}
I'm not really sure what could be causing this. I would appreciate any ideas.
This problem is not related to generics, it's a limitation of Spring AOP.
If aspects (including #Transactional aspect) are applied to the class using CGLIB proxy (this happens if target class doesn't implement any interfaces or if AOP is configured with proxy-target-class = "true"), no-argument constructor is required:
public class GenericJpaDAO <T extends HavingID> {
...
public GenericJpaDAO() {}
public GenericJpaDAO( Class entityClass, String entityName,
EntityManagerFactory emFactory ) { ... }
...
}
See also:
7.6 Proxying mechanisms

Resources