1. 程式人生 > >Spring 和 java 反射及自定義註解的問題解決!!

Spring 和 java 反射及自定義註解的問題解決!!

我想做一個將  使用者操作記錄儲存到資料庫的功能,利用java 的反射和自定義annotation 來實現,具體程式碼如下:

自定義annotation  類:



package com.util;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)    
@Retention(RetentionPolicy.RUNTIME)    
@Documented   
@Inherited  
public @interface MyAnnotation {
   
     String description() default "miss description";
   

}




UserServiceImp.java   帶自定義註解的程式碼片段:
 @MyAnnotation(description="查詢使用者")
   public boolean findUser(User user) {
    // TODO Auto-generated method stub
    return userDao.findUserByUser(user);
}






切面類:

MyAspect.java



package com.util;

import java.lang.reflect.Method;
import java.util.Calendar;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import org.aspectj.lang.JoinPoint;
import org.springframework.stereotype.Component;

import com.dao.LoggDao;
import com.model.Logg;
import com.model.User;




/*@Component("myAspect")*/
public class MyAspect {
  
    private HttpServletRequest request;
   private LoggDao loggDao;   
   
     public LoggDao getLoggDao() {
    return loggDao;
}

     
     @Resource
public void setLoggDao(LoggDao loggDao) {
    this.loggDao = loggDao;
}

    public void  dobefore(JoinPoint  jp) throws SecurityException, NoSuchMethodException{
    Class<?> targetClass=jp.getTarget().getClass();
        String methodName=jp.getSignature().getName();
   Method method=targetClass.getMethod(methodName,new Class[0]);

        MyAnnotation annotation=method.getAnnotation(MyAnnotation.class);
        String description=annotation.description();
       
       
        Calendar now = Calendar.getInstance();
        request=ServletActionContext.getRequest ();
        User user=(User)request.getSession().getAttribute("user");
         String logStr= "log Begining method: " 
                + jp.getTarget().getClass().getName() + "." 
                         + jp.getSignature().getName();
         
         
         Logg logg=new Logg();
         logg.setUser(user);
         logg.setFunction(jp.getSignature().getName());
         logg.setActionDate(now.getTime());
         logg.setMsg(logStr);
       // logg.setDescription(description);
         loggDao.addLog(logg);
         

     }
     
   
   
}



Spring  的配置檔案:
<?xml version="1.0" encoding="UTF-8" ?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd  
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd  
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
  <context:annotation-config/>
  <context:component-scan base-package="com"/>


 
   

     <bean id ="dataSource"  class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > 
         <property name="driverClassName" > 
             <value>com.mysql.jdbc.Driver</value> 
         </property > 
         <property name="url"> 
             <value> jdbc:mysql://localhost:3306/hibernate</value> 
         </property> 
         <property name ="username"> 
             <value>root</value > 
         </property > 
         <property name ="password" > 
             <value>xushigang1986</value> 
         </property > 
      
     </bean > 
    
      <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" >
         <property name="dataSource" ref="dataSource" />
         <property name="packagesToScan">
              <list>
                <value>com.model</value>
            
              </list>
         </property>
         <property name="hibernateProperties">
               <props>
                  <prop key="hibernate.dialect">
                      org.hibernate.dialect.MySQLDialect
                  </prop>
                  <prop key="hibernate.show_sql">true</prop>
                   <prop key="hibernate.hbm2ddl.auto">update</prop>
                 
              </props>   
          </property>
       </bean>
      
       <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
          <property name="sessionFactory" ref="sessionFactory">
          </property>
     </bean>
    
    
    

    <aop:config>
           <aop:aspect id="aopService" ref="myAspect">
               <aop:pointcut id="businessService" expression="execution(* com.service.imp.*.*(..))"/>
               <aop:before pointcut-ref="businessService" method="dobefore"/>
           </aop:aspect>
    </aop:config>
   
    <bean id="myAspect" class="com.util.MyAspect"></bean>

  
    <aop:aspectj-autoproxy proxy-target-class="true"/>

</beans>







UuserAction 類
該類是一個   pojo 類,在查資料時,說是如果Action 類繼承了ActionSupport 類就不能實現這樣的反射機制,所以我將UserAction 類改成了POJO 類。
網上說需要加 <aop:aspectj-autoproxy proxy-target-class="true"/> ,使Spring 來代替java SDK  來實現反射。在Spring 配置檔案中,也加了這個配置。






啟動Tomcat 並訪問了
UserServiceImp類中的findUser(User user)方法後,
Tomcat 報錯:

SEVERE: Servlet.service() for servlet default threw exception
java.lang.NoSuchMethodException: com.service.imp.UserServiceImp.findUser()
    at java.lang.Class.getMethod(Class.java:1605)
    at com.util.MyAspect.dobefore(MyAspect.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:609)
    at org.springframework.aop.aspectj.AspectJMethodBeforeAdvice.before(AspectJMethodBeforeAdvice.java:39)
    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:49)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
    at com.service.imp.UserServiceImp$$EnhancerByCGLIB$$7d56e110.findUser(<generated>)
    at com.action.LoginValidAction.validLogin(LoginValidAction.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:404)
    at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:267)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:229)
    at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:221)
    at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:86)
。。。。。




昨天已經試了一天,把網上所有能夠用上的方法都試過了一遍,還是遇到上面的問題。

後來自己想了另外一條思路來解決這個問題:

Class<?> targetClass=jp.getTarget().getClass();
        String methodName=jp.getSignature().getName();          //獲取到呼叫方法的方法名
   Method[] methods=targetClass.getMethods();         //獲取該類下的所有方法
   Method method=null;
   for(int i=0;i<methods.length;i++){               
       boolean anMethod=methods[i].isAnnotationPresent(MyAnnotation.class);

                          // 判斷某個方法是否具有  Myannotation 的自定義註解
                 if(anMethod){
          String methodStr=methods[i].toString();
    String methodName2=      methodStr.substring(0,methodStr.lastIndexOf("("));
    String methodName3=methodName2.substring(methodName2.lastIndexOf(".")+1);

                     //如果具有Myannotation 自定義註解,則取出該方法的方法名

      if(methodName3.equals(methodName)){

        //判斷方法名和呼叫方法名是否相等
        System.out.println("aaaaaaaaaa");
        method=methods[i];
        //返回該方法,並跳出for 迴圈
        break;
       
    }
       }
      
   }
  

        MyAnnotation annotation=method.getAnnotation(MyAnnotation.class);
        String description=annotation.description();
       
       
        Calendar now = Calendar.getInstance();
        request=ServletActionContext.getRequest ();
        User user=(User)request.getSession().getAttribute("user");
         String logStr= "log Begining method: " 
                + jp.getTarget().getClass().getName() + "." 
                         + jp.getSignature().getName();
         
         
         Logg logg=new Logg();
         logg.setUser(user);
         logg.setFunction(jp.getSignature().getName());
         logg.setActionDate(now.getTime());
         logg.setMsg(logStr);
      logg.setDescription(description);
         loggDao.addLog(logg);

//通過進一步測試,該解決思路符合要求

另:繼續求原來的解決方法,麻煩各位幫我看看問題出在哪裡

通過進一步的測試,我將POJO 型別的Action 類改成了extends  ActionSupport   ,並將

<aop:aspectj-autoproxy proxy-target-class="true"/> 從Spring 的配置檔案中刪除,該功能沒有收到任何影響