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 的配置檔案中刪除,該功能沒有收到任何影響