java自定义注解以及原理

自定义注解应用举例

在springmvcconfig中定义前置通知,代码如下:
import java.util.Arrays;
import java.util.List;

import com.puhui.flowplatform.manage.filter.RightFilter;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.puhui.flowplatform.manage.interceptor.BeforeControllerInterceptor;

@Configuration
public class SpringMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List> converters) {
        super.configureMessageConverters(converters);
        // 初始化转换器
        FastJsonHttpMessageConverter fastConvert = new FastJsonHttpMessageConverter();
        // 初始化一个转换器配置
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        // 将配置设置给转换器并添加到HttpMessageConverter转换器列表中
        fastConvert.setFastJsonConfig(fastJsonConfig);
        converters.add(fastConvert);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/swagger-ui.html").addResourceLocations(
                ResourceUtils.CLASSPATH_URL_PREFIX + "/META-INF/resources/");
        registry.addResourceHandler("/static/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static/",
                ResourceUtils.CLASSPATH_URL_PREFIX + "/dist/static/");
        registry.addResourceHandler("/page/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/dist/");
        super.addResourceHandlers(registry);
    }

    @Bean
    public ViewResolver viewResolver() {
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
        resolver.setCache(true);
        resolver.setPrefix(ResourceUtils.CLASSPATH_URL_PREFIX + "templates/");
        resolver.setSuffix(".ftl");
        resolver.setContentType("text/html; charset=UTF-8");
        return resolver;
    }

    // 创建Advice或Advisor
    @Bean
    public BeforeAdvice beforeControllerInterceptor() {
        return new BeforeControllerInterceptor();
    }

    @Bean
    public BeanNameAutoProxyCreator beanBeforeAutoProxyCreator() {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setProxyTargetClass(true);
        // 设置要创建代理的那些Bean的名字
        beanNameAutoProxyCreator.setBeanNames("*Controller");
        // 设置拦截链名字(这些拦截器是有先后顺序的)
        beanNameAutoProxyCreator.setInterceptorNames("beforeControllerInterceptor");
        return beanNameAutoProxyCreator;
    }

    @Bean(name = "rightFilter")
    public FilterRegistrationBean  addRightFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new RightFilter());
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/api/*"));

        return filterRegistrationBean;
    }
}

BeforeControllerInterceptor代码如下:
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;

import com.puhui.flowplatform.common.constants.MegCodeEnums.ResponseCodeEnum;
import com.puhui.flowplatform.common.exception.ServiceException;
import com.puhui.flowplatform.common.model.platform.User;
import com.puhui.flowplatform.common.model.platform.app.AppRequestParam;
import com.puhui.flowplatform.common.utils.CommonUtils;
import com.puhui.flowplatform.manage.annotation.RequiredInterceptor;
import com.puhui.flowplatform.manage.utils.RedisTemplateOperate;


public class BeforeControllerInterceptor implements MethodBeforeAdvice {

    private static final Logger log = LoggerFactory.getLogger(BeforeControllerInterceptor.class);

    @Autowired
    private RedisTemplateOperate redisTmp;

    @SuppressWarnings("rawtypes")
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        RequiredInterceptor requiredInterceptor = AnnotationUtils.findAnnotation(arg0, RequiredInterceptor.class);
        if (requiredInterceptor != null) {
            // 检验token
            AppRequestParam appRequestParam = (AppRequestParam) arg1[0];
            String token = appRequestParam.getComm().getToken();
            if (!redisTmp.hasKey(token)) {
                log.info("token:{}已经失效", token);
                throw new ServiceException(ResponseCodeEnum.C808.getCode());
            } else {
                User user = CommonUtils.getCurUser(token);
                if (null == user) {
                    redisTmp.delete(token);
                    log.error("token:{}已经失效", appRequestParam.toString());
                    throw new ServiceException(ResponseCodeEnum.C808.getCode());
                }
            }
        }
    }
}

Annotation定义如下

package com.puhui.flowplatform.manage.annotation;

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public abstract @interface RequiredInterceptor {
    boolean required() default true;
}


1 自定义注解,采用@interface ,可以根据需求定义方法体
2 应用注解到要拦截到方法上

@RequiredInterceptor(required = true)
3. 拦截器进行拦截,发现方法定义了@requiredInterceptor 注解后,进行特定到业务逻辑判断

其实注解只是一个flag到作用,主要到拦截逻辑还是拦截器生效。
我们也可以定一个注解,检查权限,@requiredPermission,然后配置前置通知,在拦截器里面判断有这个注解到,进行权限校验。

public class BeforeControllerInterceptor implements MethodBeforeAdvice {

    private static final Logger log = LoggerFactory.getLogger(BeforeControllerInterceptor.class);

    @Autowired
    private RedisTemplateOperate redisTmp;

    @SuppressWarnings("rawtypes")
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        RequiredInterceptor requiredInterceptor = AnnotationUtils.findAnnotation(arg0, RequiredInterceptor.class);
        if (requiredInterceptor != null) {
            // 检验token
            AppRequestParam appRequestParam = (AppRequestParam) arg1[0];
            String token = appRequestParam.getComm().getToken();
            if (!redisTmp.hasKey(token)) {
                log.info("token:{}已经失效", token);
                throw new ServiceException(ResponseCodeEnum.C808.getCode());
            } else {
                User user = CommonUtils.getCurUser(token);
                if (null == user) {
                    redisTmp.delete(token);
                    log.error("token:{}已经失效", appRequestParam.toString());
                    throw new ServiceException(ResponseCodeEnum.C808.getCode());
                }
            }
        }
    }
}

Method: 拦截到方法对象
public com.puhui.flowplatform.common.model.Response com.puhui.flowplatform.manage.controller.RoleController.getRolesList(java.lang.String,java.lang.String,javax.servlet.http.HttpServletRequest)
arg1:方法到参数,是一个数组,里面有方法到所有参数
arg2: 方法所在的对象

上述例子是通过spring提供的工具栏annotationUtil去查询是否有annotations。 也可以通过下面的方法:
public static void main(String[] args) {
    try {
    for (Method method : AnnotationParsing.class
        .getClassLoader()
        .loadClass(('com.journaldev.annotations.AnnotationExample'))
        .getMethods()) {
        // checks if MethodInfo annotation is present for the method
        if (method.isAnnotationPresent(com.journaldev.annotations.MethodInfo.class)) {
            try {
        // iterates all the annotations available in the method
                for (Annotation anno : method.getDeclaredAnnotations()) {
                    System.out.println('Annotation in Method ''+ method + '' : ' + anno);
                    }
                MethodInfo methodAnno = method.getAnnotation(MethodInfo.class);
                if (methodAnno.revision() == 1) {
                    System.out.println('Method with revision no 1 = '+ method);
                    }
 
            } catch (Throwable ex) {
                    ex.printStackTrace();
                    }
        }
    }
    } catch (SecurityException | ClassNotFoundException e) {
            e.printStackTrace();
         }
    }
 
}


 注解解释及原理


注解是标记,也可以理解成是一种应用在类、方法、参数、属性、构造器上的特殊修饰符。注解作用有以下三种:

       第一种:生成文档,常用的有@param@return等。

       第二种:替代配置文件的作用,尤其是在spring等一些框架中,使用注解可以大量的减少配置文件的数量。

       第三种:检查代码的格式,如@Override,标识某一个方法是否覆盖了它的父类的方法。


注解的底层也是使用反射实现的

你可能感兴趣的:(java技术)