有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何编写像ibatis Select注解一样工作的spring自定义注解?

我正在尝试创建一个自定义注释,如ibatis@Select

总之,目标是

  • 将一些数据附加到方法具有自定义注释的参数中

首先看一下端点-ArtistNodeRepository.java

@Repository
public interface ArtistNodeRepository {

    @CreateNode(tid = "artist")
    public Node create(Map data) throws Exception;
}

要对CreateNode注释执行的操作是将data.put("type", "artist")放入参数映射中

下面是注释-CreateNode.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface CreateNode {
    String[] values() default "";
    String tid();
}

对于控制器注释,我准备了这个BeanPostProcessor-NodeAnnotationProcessor.java

@Component
public class NodeAnnotationProcessor implements BeanPostProcessor {

    private ConfigurableListableBeanFactory configurableListableBeanFactory;

    @Autowired
    public NodeAnnotationProcessor(ConfigurableListableBeanFactory configurableListableBeanFactory) {
        super();
        this.configurableListableBeanFactory = configurableListableBeanFactory;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        this.scanNodeAnnotation(bean, beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
       // this.scanNodeAnnotation(bean, beanName);
        return bean;
    }

    protected void scanNodeAnnotation(Object bean, String beanName){
        this.configureMethodAction(bean);
    }

    private void configureMethodAction(Object bean){
        Class<?> managedBeanClass = bean.getClass();
        ReflectionUtils.MethodCallback methodCallback = new NodeMethodCallback(configurableListableBeanFactory, bean);
        ReflectionUtils.doWithMethods(managedBeanClass, methodCallback);
    }
}

我不清楚把MethodCallback放在哪里postProcessBeforeInitializationpostProcessAfterInitialization。在我看来,它应该在after中,因为我正在尝试操作该方法的参数

最后,这是MethodCallback-NodeMethodCallback.java

public class NodeMethodCallback implements ReflectionUtils.MethodCallback {

    private Logger logger = LoggerFactory.getLogger(NodeMethodCallback.class);

    private ConfigurableListableBeanFactory beanFactory;
    private Object bean;
    private static int AUTOWIRE_MODE = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;

    public NodeMethodCallback(ConfigurableListableBeanFactory beanFactory, Object bean) {
        this.beanFactory = beanFactory;
        this.bean = bean;
    }

    @Override
    public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {

        logger.info("doWith method info :: " + String.valueOf(bean) + "." + bean.getClass().getName());
        /*
            What I expected is Printing ArtistNodeRepository Class with create Method
            But It prints something like ...

            SessionFlashMapManager
            DefaultRequestToViewNameTranslator
            ...
        */


        try {
           logger.info("When I call you :: " + method.getName()); // I expect method which contains @CreateNode annotation, but it is not ...
            Annotation[] methodAnnotations = method.getDeclaredAnnotations();
            boolean isTarget = false;
            String tid = "";
            for(Annotation anno : methodAnnotations) {
                logger.info("annotation Class :: " + anno.getClass().getName());
                if(isTarget) break;
                if(anno instanceof CreateNode) {
                    logger.info("CreateNode annotation found");
                    CreateNode createNode = method.getDeclaredAnnotation(CreateNode.class);
                    tid = createNode.tid();
                    isTarget = true;
                } 
            }
            if(!isTarget) return;
            ReflectionUtils.makeAccessible(method);

            /*
                Do Somthing with Parameter ...
                Do Somthing with Parameter ...
                Do Somthing with Parameter ...
                Do Somthing with Parameter ...
                Do Somthing with Parameter ...
            */
        } catch (Exception e ){
            logger.error("ERROR", e);
        }
    }
}

问题是。。。在doWith中,我找不到ArtistNodeRepository实例

我应该如何利用{}和{}来实现目标

好的示例代码和好的答案一样好


共 (1) 个答案

  1. # 1 楼答案

    我想你误解了ReflectionUtils.doWithMethods的用法。这意味着如果匹配回调,则迭代类方法。而不是在调用方法回调时

      public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
            // Keep backing up the inheritance hierarchy.
            Method[] methods = getDeclaredMethods(clazz);
            for (Method method : methods) {
                if (mf != null && !mf.matches(method)) {
                    continue;
                }
                try {
                    mc.doWith(method);
                }
                catch (IllegalAccessException ex) {
                    throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
                }
            }
            if (clazz.getSuperclass() != null) {
                doWithMethods(clazz.getSuperclass(), mc, mf);
            }
            else if (clazz.isInterface()) {
                for (Class<?> superIfc : clazz.getInterfaces()) {
                    doWithMethods(superIfc, mc, mf);
                }
            }
        }
    

    我想你可以用aspect。像这样

        @Around("execution(public * org.springframework.data.jpa.repository.JpaRepository+.*(..))")
        // @Around("@annotation(Repository)")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            CreateNode createNode = method.getAnnotation(CreateNode.class);
            if(createNode != null) {
                Object[] args = joinPoint.getArgs();
                // do your business
    
            }
            return joinPoint.proceed();
        }
    

    希望能帮助你