【Java】——自定义注解对参数进行校验、spring扫描自定义注解

前提

    上篇博客中详细介绍自定义注解的使用,本文主要是对自定义注解的进一步深入。会使用CGLIb进行动态代理来完成对方法参数是否为空的判断,以及再spring中如何扫描自定义注解

自定义注解对方法参数为空校验

为什么要用动态代理?

因为Java的反射拿不到参数的相关信息,对方法参数进行校验,肯定是要在方法执行前进行校验,所以就需要动态代理来完成。对真实的对象进行代理,让代理对象执行参数校验这一部分的操作。

1、自定义注解

@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String msg() default "参数不能为空";
}

2、代理类以及校验方法

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class HelloServiceCgLib implements MethodInterceptor {
    private Class target;

    public Object getInstance(Class target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
        System.out.println("我是CGLIB的动态代理");
        System.out.println("我准备执行了");
        if (!check(method,objects)) {
            System.out.println("我没能成功执行");
            return false;
        }
            Object returnObj = proxy.invokeSuper(object, objects);
            System.out.println("我已经正确执行过了");
            return returnObj;
    }

    /**
     * 对参数校验的方法
     * @param method 目标方法
     * @param objects 相关参数值
     * @return
     */
    public  boolean check(Method method,Object[] objects)  {
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i <parameters.length; i++) {
           Parameter parameter = parameters[i];
            if (parameter.isAnnotationPresent(MyAnnotation.class)) {
                MyAnnotation annotation = parameter.getAnnotation(MyAnnotation.class);
                if (objects==null ||objects[i]==null) {
                    System.out.println(parameter.getName()+annotation.msg());
                    return false;
                }
            }
        }
        return true;
    }
}

3、真实类

public class Hello {
    public void sayHello(@MyAnnotation String name,@MyAnnotation String start) {
        System.out.println("hello "+name);
        System.out.println(start);
    }
}

4、调用过程

public class AnnotationTest {
    public static void main(String[] args) {
                HelloServiceCgLib helloServiceCgLib = new HelloServiceCgLib();
        Hello proxy = (Hello) helloServiceCgLib.getInstance(Hello.class);
        proxy.sayHello("world",null);
    }

5、执行结果


对第二个参数进行拦截,判断为空,阻止方法的非正常执行。

spring扫描自定义注解

在使用Spring的时候需要自定义annotation来满足项目需求。

    在Bean初始化的过程都会调用BeanPostProcessor接口即Spring中的后置处理器,这个接口是Spring IOC容器给我们提供扩展接口,方便在Spring容器中完成bean实例化,配置以及其他初始化方法前后添加一些自己处理的逻辑。

    在bean创建好之后都会调用后置处理器的postProcessAfterInitialization方法,所以可以利用自定义这个方法,达到让spring扫描自定义注解的目的。

1、自定义注解

@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyListener {
    String value() default "spring";
}

2、配置spring扫描

@Component
public class MyListenerProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
        if (methods != null) {
            for (Method method : methods) {
                MyListener myListener = AnnotationUtils.findAnnotation(method, MyListener.class);
                // process
                if (myListener != null) {
                    System.out.println(method.getName());
                    System.out.println(myListener.value());
                }

            }
        }
        return bean;
    }
}

3、配置要扫描的方法

@Service
public class MyService {

    @MyListener
    public void onMessage() {
        System.out.println("我被调用了");
    }
}

4、初始化,判断spring是否正确扫描注解

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
        MyService bean = ac.getBean(MyService.class);}
    }

5、注解被spring扫描到了


总结

    通过对自定义注解的使用可以很好加深对动态代理这些概念的认识,对spring框架的理解同样可以更进一步。

  • 6
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
你可以使用自定义注解校验请求参数。下面是一个示例: 首先,创建一个自定义注解类,例如 `@RequestParamValid`: ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface RequestParamValid { String value() default ""; } ``` 然后,在你的控制器方法中使用 `@RequestParamValid` 注解来标记需要校验参数: ```java @PostMapping("/example") public String exampleMethod(@RequestParam @RequestParamValid String parameter) { // ... } ``` 接下来,你可以创建一个切面来处理参数校验逻辑。切面可以使用 Spring 提供的 `HandlerMethodArgumentResolver` 接口来实现: ```java import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; @Component public class RequestParamValidResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestParamValid.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 在这里进行参数校验逻辑,可以使用各种方式来校验参数 // 例如,你可以使用 Hibernate Validator 进行校验 // 如果参数校验失败,可以抛出异常或返回错误信息 // 如果参数校验通过,可以返回参数的值 // 这里只是一个示例,假设参数不能为空 Object argumentValue = webRequest.getParameter(parameter.getParameterName()); if (argumentValue == null || argumentValue.toString().isEmpty()) { throw new IllegalArgumentException("参数校验失败"); } return argumentValue; } } ``` 最后,将切面注册到 Spring 容器中,以便生效。你可以在配置类中使用 `@EnableWebMvc` 注解来开启 Spring MVC 的相关功能: ```java import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { private final RequestParamValidResolver requestParamValidResolver; public WebConfig(RequestParamValidResolver requestParamValidResolver) { this.requestParamValidResolver = requestParamValidResolver; } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(requestParamValidResolver); } } ``` 现在,当请求进入控制器方法时,会自动触发参数校验逻辑。如果参数校验失败,将会抛出异常或返回错误信息。如果校验通过,控制器方法将会正常执行。 这只是一个简单的示例,你可以根据实际需求进行更复杂的参数校验逻辑。希望对你有帮助!如有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mandy_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值