I was reading the example available here: https://www.mkyong.com/spring/spring-aop-examples-advice , and I tried to implement an example, adapting the code to my previous project. I have a single web application that saves in a DB the name and the country of a given person, and I wanted to "intercept" the execution of the operations like updates or deletions.
I'm new into the whole Spring+Hibernate world so I don't know if I'm wrong with my code. So I'll leave you here some code examples:
My project structure:
Package AOP
- HijackAroundMethod.java
Package Controller
- PersonController.java
Package DAO
PersonDAO.java
PersonDAOImpl.java
Package Model
- Person.java
Package Service
PersonService.java
PersonServiceImpl.java
The advice method (as seen in the page mentioned before):
public class HijackAroundMethod implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Method name: "+ invocation.getMethod().getName());
System.out.println("Method arguments: " + Arrays.toString(invocation.getArguments()));
System.out.println("Before executing operation");
try{
Object result = invocation.proceed();
System.out.println("After executing method");
return result;
}catch(IllegalArgumentException e){
System.out.println("Exception catched");
throw e;
}
}
An example of my DAO class (here's where I implement the functions related with DB persistance):
@Repository
public class PersonDAOImpl extends HibernateDaoSupport implements PersonDAO {
private static final Logger logger = LoggerFactory.getLogger(PersonDAOImpl.class);
@Autowired
private SessionFactory sessionFactory;
@Autowired
public PersonDAOImpl(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
@Override
@Transactional
public void addPerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(p);
logger.info("Person saved successfully, Person Details="+p);
}
@Override
@Transactional
public void updatePerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.update(p);
logger.info("Person updated successfully, Person Details="+p);
}
This is what I added to my servlet-content.xml (where I define the beans configuration):
<bean id="PersonDAOImpl" class="com.dacasals.raspertwo.dao.PersonDAOImpl"/>
<bean id="HijackAroundMethod" class="com.dacasals.raspertwo.aop.HijackAroundMethod"/>
<bean id="PersonDAOImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="PersonDAOImpl"/>
<property name="interceptorNames">
<list>
<value>HijackAroundMethod</value>
</list>
</property>
</bean>
When I run this in my server (I'm using STS 3.8.1 with Tomcat 7), I get the following error:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.dacasals.raspertwo.dao.PersonDAO] is defined: expected single matching bean but found 3: PersonDAOImpl,PersonDAOImplProxy,personDAOImpl
org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:172)
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1106)
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1219)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207)
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1128)
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1219)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:751)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:682)
org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:553)
org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:494)
org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
javax.servlet.GenericServlet.init(GenericServlet.java:160)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
I've been reading some questions here in stackoverflow, but I can't find any case similar to mine.
There is some misunderstaning with spring configuration
When you put the annotation @Repository
on the class PersonDAOImpl
spring, by using autoscanning, creates a bean called personDAOImpl and his bean implements the interface PersonDAO
Then you use the configuration file. Here you declare this:
<bean id="PersonDAOImpl" class="com.dacasals.raspertwo.dao.PersonDAOImpl"/>
In this case spring creates a new bean called PersonDAOImpl and this bean implements PersonDAO
and it has a different name respect to the previous one (the first character is upper case)
Finally always in the configuration file you declare:
<bean id="PersonDAOImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="PersonDAOImpl"/>
<property name="interceptorNames">
<list>
<value>HijackAroundMethod</value>
</list>
</property>
</bean>
This is a new "proxied bean" whose final class is PersonDAOImpl
and this bean name is PersonDAOImplProxy . Also this bean implements PersonDAO
At this point you have three different beans all implementing the same interface. Beans are:
When you try to inject one bean in another bean by using @Autowired
you can't simply use this syntax:
@Autowired
private PersonDAO myDao;
Spring doesn't know which one of the 3 beans should inject. So you must tell spring to use one of the 3. This is done by using the @Qualifier
annotation. Let's suppose you want to inject the proxyed bean you should use something like this:
@Autowired
@Qualifier("PersonDAOImplProxy")
private PersonDAO myDao;
In this way spring knows that it must inject a bean implementing the interface PersonDAO
and it knows that you want to use the proxyed bean
In anycase I think you would like to use just one of the beans so you should check your spring configuration and optimize it
I hope this is usefull
Angelo
Well, after some days I decided to try another way to use aspects on my application and now is working fine.
I read the book "Spring in action" 4th edition, and I found there good examples of aspects. Instead of using a "Hijack" class, I declared a new class using anotations such as @Pointcut, @After and @Before. Then, I was able to "listen" to the operations executed by my classes.
Although my goal is to create a generic way to "listen" events in Spring+Hibernate, this was a good start. Too bad I couldn't run the example provided by the web site I visited before. Thanks to everyone for your advices, soon I'll be asking again.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.