简体   繁体   中英

Error while programing Spring AOP+Hibernate

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:

  1. personDAOImpl
  2. PersonDAOImpl
  3. PersonDAOImplProxy

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM