java注解(java Annotation)

1,什么是注解?

注解是一种元数据,就是描述java代码的数据。用于给java的类型、方法、属性、参数、代码等添加修饰。注意:注解本身仅仅只是元数据,不含业务逻辑。实际解析元模型的代码负责根据注解来赋予业务逻辑。(所谓元数据就是:描述数据的数据。)

2,注解有什么用?

注解的用处就是描述java代码元素,Java程序中通过注解,可以简洁、优雅的给代码添加修饰。java提供了4种元注解(就是对注解的描述,用于描述注解的注解),这4中元注解,确定了注解对java代码。如下:

@Documented //注解是否将包含在JavaDoc中;描述注解是否具有
@Retention //定义该注解的生命周期;包括:RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME;明确注解作用在源码阶段、编译阶段、运行期。
@Target //注解用于什么地方;参见枚举ElementType;不设定,则默认所有java元素都可以使用;
/**
 *ElementType.TYPE(可用于类、接口、注解类型、枚举)
 *ElementType.FIELD(可用于成员变量、枚举常量)
 *ElementType.METHOD(用于方法,静态方法、非静态方法,不能用于构造方法)
 *ElementType.PARAMETER(用于参数(方法形参))
 *ElementType.CONSTRUCTOR(用于构造器)
 *ElementType.LOCAL_VARIABLE(用于方法局部变量)
 *ElementType.ANNOTATION_TYPE(用于注解类型)
 *ElementType.PACKAGE(用于包类型,只能用在package-info.java文件中)
 *ElementType.TYPE_PARAMETER(用于类型参数,即泛型方法、泛型类、泛型接口)
 */

@Inherited //是否允许子类继承该注解

其中,生命期为:RetentionPolicy.RUNTIME的注解,能够在代码实际运行时,动态添加功能。而动态添加功能本身是复杂的,由注解在实际解析时,通过反射判断是否存在对应注解,如果存在,根据注解的属性参数,完成逻辑处理。实际使用注解,则非常简洁、易读,屏蔽复杂性,将注意力集中当前的业务逻辑实现上。

3,怎么使用注解?

注解一旦定义,包括注解本身、注解解析机制等完成后,注解的实际使用就非常简单,只需要了解注解的@Target,在合适的java代码元素上标注就完成注解的使用。如下:

@Component
@MailEventProcessor("mailone")
public class ConcreteMailSender extends BaseMailSender {

    @Override
    public void sendMail(MailSenderContext mailCxt) throws Exception {
        //处理邮件发送        
    }

}

4,利用spring框架自定义类注解

自定义注解:

/**
 * 该注解描述邮件处理器处理的具体邮件类型;value为邮件标识;
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MailEventProcessor {
    String value() default "";
}

注解修饰类生效方式一:

通过spring的扩展点实现,本例采用BeanPostProcessor实现,根据需要可以采用其它spring扩展点实现,比如:BeanFactoryPostProcessor的扩展类的扩展点等处理注解;

MailEventConfigProcessor:

@Component
class MailEventConfigProcessor implements BeanPostProcessor {

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

    @Override
    public Object postProcessAfterInitialization(Object bean,
            String beanName) throws BeansException {
        final Class<? extends Object> clazz = bean.getClass();
         final MailEventProcessor mailEventProcessor = (MailEventProcessor) clazz.getAnnotation(MailEventProcessor.class);
         if (null != mailEventProcessor) {
             final String mailType = mailEventProcessor.value();
             if (!StringUtils.isNullOrEmpty(mailType)) {
                 if (bean instanceof BaseMailSender)
                 MailProcessorUtils.map.put(mailType, (BaseMailSender)bean);
             }
         }
        return bean;
    }
}

MailProcessorUtils:

public final class MailProcessorUtils {
    public static Map<String, BaseMailSender> map = new ConcurrentHashMap<String, BaseMailSender>();

    // 通过邮件类型,发送邮件
    public static void sendMail(final String strMailType, final MailSenderContext mailCxt) throws Exception {
        if (map.containsKey(strMailType)) {
            BaseMailSender sender = map.get(strMailType);
            sender.sendMail(mailCxt);
        }
    }
}

事件接受处理时,直接如下调用:

MailProcessorUtils.sendMail("mailone", theContext);

注解修饰生效方式二:

自定义扫描,并获取注解信息进行处理;

1,loader来扫描;

@Component
public class MailProcessorScanLoader implements ResourceLoaderAware {
    ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);

    private static Map<String, BaseMailSender> map = null;

    public Map<String, BaseMailSender> getProcessorMap () {
        if (null == map) {
            initSenderMap();
        }
        return map;
    }

    private void initSenderMap() {
        map = new ConcurrentHashMap<String, BaseMailSender>();
        Set<Class<?>> classList = this.scan("com.gj.springboot.restful.email");
        for (Class<?> clazz : classList) {
            MailEventProcessor anno = (MailEventProcessor) clazz.getAnnotation(MailEventProcessor.class);
            if (null != anno) {
                String strMailType = anno.value();
                // 注解值为key存放bean
                if (BaseMailSender.class.isAssignableFrom(clazz)) {
                    map.put(strMailType, (BaseMailSender) SpringBeanUtils.getBean(clazz));
                }

            }
        }
    }

    private Set<Class<?>> scan(final String basePackage) {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                    + org.springframework.util.ClassUtils.convertClassNameToResourcePath(
                            SystemPropertyUtils.resolvePlaceholders(basePackage))
                    + "/**/*.class";
            Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);

            for (int i = 0; i < resources.length; i++) {
                Resource resource = resources[i];
                if (resource.isReadable()) {
                    MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
                    try {
                        classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return classes;

    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
    }
}

2,调用扫描,并提供发送方法:

MailScanProcessorUtils:

@Component
public class MailScanProcessorUtils {

    @Autowired
    private MailProcessorScanLoader mailProcessorScanLoader;

    // 通过邮件类型,发送邮件
    public void sendMail(final String strMailType, final MailSenderContext mailCxt) throws Exception {
        Map<String, BaseMailSender> map = mailProcessorScanLoader.getProcessorMap();
        System.out.println("map daxiao:" + map.size());
        if (map.containsKey(strMailType)) {
            BaseMailSender sender = map.get(strMailType);
            sender.sendMail(mailCxt);
        }
    }

}

事件接受处理时,直接如下调用:

mailScanProcessorUtils.sendMail("mailone", theContext);

比较起来,第一种方法更简单直接,一般没有必要把被注解修饰的类放在spring启动扫描外的路径。

上面两种方式,都可以扩展,解析ElementType.METHOD 注解,修饰方法功能;但是一般情况下,有更简单、更好的方式。参见下节。

5,利用spring框架自定义method注解;

采用spring 提供的AOP扩展来实现;

1,定义注解


/**
 * 安全权限验证;
 * 
 * @author gaojun
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Security {

    String value() default "";
}

2,添加切面,并绑定注解;


@Component
@Aspect
public class Authorizer {
    @Pointcut("@annotation(com.gj.springboot.restful.annotation.Security)")
    private void cut() { }

    /**
     * 定制一个环绕通知
     * @param joinPoint
     */
    @Around("cut()&&@annotation(security)")
    public Object around(ProceedingJoinPoint joinPoint, Security security){
        System.out.println("around通知之开始");
        Object result = null;
        String strOperater = security.value();
        // TODO 获取当前人员是否具有对应配置的权限;
        if ("operaterone".equals(strOperater)) {
            try {
                result = joinPoint.proceed();
            } catch (Throwable e) {
                //异常处理类似,只是需要定义返回类型,包装信息;
                e.printStackTrace();
            }
        }
        System.out.println("around通知之结束");
        return result;
    }

}

3,使用直接在需要的方法上面添加注解即可:

    @Security("operaterone")
    public String  list(Model model) throws Exception{

6,spring AOP基础参考:

【spring-boot】spring aop 面向切面编程初接触

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值