Spring 和 java 反射及自定义注解的问题解决!!

本文介绍使用Java反射技术和AOP实现用户操作记录保存至数据库的功能。通过自定义注解和Spring AOP进行方法级别的拦截,记录用户行为。文章详细展示了自定义注解、切面类及Spring配置等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我想做一个将 用户操作记录保存到数据库的功能,利用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 的配置文件中删除,该功能没有收到任何影响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值