注释嵌套注释_DIY注释

注释嵌套注释

从Java 5开始,Java中出现了注释。 我想做一个自己的注释,只是为了看看需要什么。 但是,我发现它们只是接口。

有擦

接口后面没有牙。 必须执行一些代码。 我认为这是橡胶行之有效的方法,我真的找到了解决方法。

首先,我需要一个目标

我选择了一个最近的热门话题:缓存。 我不想实现JSR 109(JCache),但也不想做典型的“ Hello World”。 我选择实现两个注释,一个注释不带任何参数,另一个注释不带参数。 我还需要一个缓存提供程序。 如果我要这样做的话,还可以将真正的缓存库加入其中。 它还遵循我的设计理念,即使用产品/库来达成目标,而不是将所有内容都进行家庭纺。 经过仔细考虑,我选择了hazelcast作为我的缓存引擎。 它是市场上最快的,而且是免费的。

更多决定

在选择了目标之后,我仍然需要找出如何在它们后面扎牙的方法。 经过一番挖掘,我发现了两种方法:

反射

几乎每次使用反射时,我都会为编写这么笨拙的代码感到遗憾。 另外,要按照我想要的方式进行操作,我必须创建自己的框架。 听起来两个注解的工作量很大。

面向方面的编程(AOP)

这非常适合我想做的事。 AOP致力于将样板代码减少到一个地方。 这将很方便并且与缓存紧密结合,因为缓存可分为以下步骤:

  1. 检查此情况是否之前已完成。
  2. 如果是这样的话:
    1. 检索存储的结果
  3. 如果不:
    1. 运行功能
    2. 存储结果
  4. 返回结果

也许这过于简单,但总的来说是正确的。 就像所有事物一样,细节决定成败。

同时,回到AOP牧场

虽然我知道AOP是适合我的地方,但我对此并不了解。 我发现Spring有一个AOP库,而众所周知的库是AspectJ。 AspectJ对我不熟悉,需要运行时引擎才能工作。 我对Spring更加熟悉,所以选择了它。 在研究Spring的AOP时,我发现我必须深入研究AspectJ的注释,因此无论如何我还是以某种形式或方式被AspectJ所困。

新概念,新词汇

编写方面不像编写对象。 它们是对象,但并非如此,因此当然需要一组新的术语。 我使用的是Spring AOP文档中的内容

我确实需要阅读几次该页面才能理解所讲的内容。 强烈建议您执行相同的操作,否则其余帖子听起来像胡言乱语。

切入点的构成和建议

切入点设计很容易,因为我只对带有注释的方法感兴趣。 它需要的建议是周围的建议,因为如果已经进行了匹配的调用,我就需要能够避免调用该方法。

最后的代码

Maven Pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.darylmathison</groupId>
    <artifactId>annotation-implementation</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>4.2.4.RELEASE</spring.version>
    </properties>

    <description>
        This project is an example of how to implement an annotation via Spring AOP.
    </description>

    <scm>
        <url>https://github.com/darylmathison/annotation-implementation-example.git</url>
        <connection>scm:git:https://github.com/darylmathison/annotation-implementation-example.git</connection>
        <developerConnection>scm:git:git@github.com:darylmathison/annotation-implementation-example.git</developerConnection>
    </scm>

    <issueManagement>
        <system>GitHub</system>
        <url>https://github.com/darylmathison/annotation-implementation-example/issues</url>
    </issueManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.8</version>
        </dependency>

        <dependency>
            <groupId>com.hazelcast</groupId>
            <artifactId>hazelcast</artifactId>
            <version>3.6</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>2.7</version>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>dependencies</report>
                            <report>index</report>
                            <report>project-team</report>
                            <report>issue-tracking</report>
                            <report>scm</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.10.3</version>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>javadoc</report>
                            <report>test-javadoc</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jxr-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <linkJavadoc>true</linkJavadoc>
                </configuration>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>jxr</report>
                            <report>test-jxr</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-changelog-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <type>range</type>
                    <range>90</range>
                </configuration>
            </plugin>
        </plugins>
    </reporting>
</project>

注释

快取

缓存注释的可爱名称,对吗?

package com.darylmathison.ai.annotation;

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

/**
 * Created by Daryl on 2/19/2016.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CacheMe {
}
CacheMeNow
package com.darylmathison.ai.annotation;

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

/**
 * Created by Daryl on 2/19/2016.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CacheMeNow {
    String key();
}

弹簧配置

我决定使用基于Java的配置,而不是像通常为了改变速度而使用的XML。 EnableAspectJAutoProxy批注是使Spring AOP开始工作的关键。 我一直在我旁边,直到我读到有关这颗小宝石的这篇文章。 有时,这是一天中最容易燃烧的事情。

AppConfig

package com.darylmathison.ai.config;

import com.darylmathison.ai.cache.CacheAspect;
import com.darylmathison.ai.service.FibonacciService;
import com.darylmathison.ai.service.FibonacciServiceImpl;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.MapConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Daryl on 2/20/2016.
 */
@Configuration
@ComponentScan(basePackages = "com.darylmathison.ai")
@EnableAspectJAutoProxy
public class AppConfig {

    @Bean
    public Map<String, Object> cache() {
        Config config = new Config();
        MapConfig mapConfig = new MapConfig();
        mapConfig.setEvictionPercentage(50);
        mapConfig.setEvictionPolicy(EvictionPolicy.LFU);
        mapConfig.setTimeToLiveSeconds(300);
        Map<String, MapConfig> mapConfigMap = new HashMap<>();
        mapConfigMap.put("cache", mapConfig);
        config.setMapConfigs(mapConfigMap);

        HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
        return instance.getMap("cache");
    }

    @Bean
    public FibonacciService fibonacci() {
        return new FibonacciServiceImpl();
    }

    @Bean
    public CacheAspect cacheAspect() {
        return new CacheAspect();
    }
}

服务编号

基于经典Spring的设计需要服务吗? 由于Spring使用代理来实现其AOP,因此强烈建议为带注释的类定义一个接口以实现。

斐波那契服务

package com.darylmathison.ai.service;

/**
 * Created by Daryl on 2/20/2016.
 */
public interface FibonacciService {

    long calculate(int rounds);

    long calculateWithKey(int rounds);
}

FibonacciServiceImpl

package com.darylmathison.ai.service;


import com.darylmathison.ai.annotation.CacheMe;
import com.darylmathison.ai.annotation.CacheMeNow;

/**
 * Created by Daryl on 2/20/2016.
 */
public class FibonacciServiceImpl implements FibonacciService {

    @Override
    @CacheMe
    public long calculate(int rounds) {
        return sharedCalculate(rounds);
    }

    @Override
    @CacheMeNow(key = "now")
    public long calculateWithKey(int rounds) {
        return sharedCalculate(rounds);
    }

    private static long sharedCalculate(int rounds) {
        long[] lastTwo = new long[] {1, 1};

        for(int i = 0; i < rounds; i++) {
            long last = lastTwo[1];
            lastTwo[1] = lastTwo[0] + lastTwo[1];
            lastTwo[0] = last;
        }

        return lastTwo[1];
    }
}

AOP的东西

这是注释实现的核心。 其他所有内容都可以用来支持后续的工作。

系统存档

根据Spring文档,集中化切入点定义是一个好主意。

package com.darylmathison.ai.cache;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * Created by Daryl on 2/20/2016.
 */
@Aspect
public class SystemArch {

    @Pointcut("@annotation(com.darylmathison.ai.annotation.CacheMe)")
    public void cacheMeCut() {

    }

    @Pointcut("@annotation(com.darylmathison.ai.annotation.CacheMeNow)")
    public void cacheMeNowCut() {

    }
}
缓存方面

周围注释使用切入点类的完整方法名称来定义建议的内容。 CacheMeNow批注的建议包括一个额外条件,因此可以定义批注,以便可以读取关键参数。 测试代码中揭示了CacheMeNow中的一个设计错误。

package com.darylmathison.ai.cache;

import com.darylmathison.ai.annotation.CacheMeNow;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

/**
 * Created by Daryl on 2/20/2016.
 */
@Aspect
public class CacheAspect {

    @Autowired
    private Map<String, Object> cache;

    @Around("com.darylmathison.ai.cache.SystemArch.cacheMeCut()")
    public Object simpleCache(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        StringBuffer keyBuffer = new StringBuffer();
        for(Object o: proceedingJoinPoint.getArgs()) {
            keyBuffer.append(o.hashCode());
        }
        String key = keyBuffer.toString();
        Object ret = cache.get(key);
        if(ret == null) {
            ret = proceedingJoinPoint.proceed();
            cache.put(key, ret);
        }
        return ret;
    }

    @Around("com.darylmathison.ai.cache.SystemArch.cacheMeNowCut() && @annotation(cacheMeNow)")
    public Object simpleCacheWithParam(ProceedingJoinPoint proceedingJoinPoint, CacheMeNow cacheMeNow) throws Throwable {
        Object ret = cache.get(cacheMeNow.key());
        if(ret == null) {
            ret = proceedingJoinPoint.proceed();
            cache.put(cacheMeNow.key(), ret);
        }
        return ret;
    }
}

测试代码

显示注释确实引起缓存的驱动程序代码。

斐波那契检验

package com.darylmathison.ai.service;

import com.darylmathison.ai.config.AppConfig;
import org.junit.Assert;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Created by Daryl on 2/20/2016.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public class FibonacciTest {

    private static final int ROUNDS = 12;
    private static final long ANSWER = 377;

    @Autowired
    private FibonacciService fibonacci;

    @org.junit.Test
    public void testCalculate() throws Exception {
        long start = System.currentTimeMillis();
        Assert.assertEquals(ANSWER, fibonacci.calculate(ROUNDS));
        long middle = System.currentTimeMillis();
        Assert.assertEquals(ANSWER, fibonacci.calculate(ROUNDS));
        long end = System.currentTimeMillis();
        Assert.assertTrue((end - middle) < (middle - start));
    }

    @org.junit.Test
    public void testCalculateWithKey() throws Exception {
        Assert.assertEquals(ANSWER, fibonacci.calculateWithKey(ROUNDS));
        // This test should not pass
        Assert.assertEquals(ANSWER, fibonacci.calculateWithKey(13));
    }
}

结论

注释不必很难实现。 使用AOP编程,我可以用很少的代码来实现两个注释。

翻译自: https://www.javacodegeeks.com/2016/03/diy-annotations-3.html

注释嵌套注释

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值