suninf 's blog

Enjoy From Programming And Technique

Java注解

Catalog

java注解常常用于自动化,简化代码开发成本,减少重复劳动,比如Spring框架使用了很多注解(如@Resource, @Service@Component等),让组件化可以非常简单的实施,而且代码清晰简洁。

常用注解

标准注解

  • @Deprecated

添加到不鼓励使用的项上,当使用这种项时,编译器会发出警告

  • @Override

表示是覆盖父类的方法,如果父类没有相同的声明,编译器能报错。

  • @PostConstruct & @PreDestroy

被标记的方法,会在对象构造之后或移除之前被调用

  • @Resource

资源注入

元注解

应用于注解的注解

  • @Target

限定注解可以应用于那些项上,取值属于枚举类型 ElementType

常用取值

类型 注解适用场合
TYPE 类,enum,接口等
METHOD 方法
CONSTRUCTOR 构造函数
FIELD 成员域
  • @Retention

表示该注解应该保留多长时间

常用RetentionPolicy.RUNTIME,这种可以通过反射API来访问注解类型。

  • @Documented

指定注解应该包含在注解项的文档中

  • @Inherited

指定一个注解,当它应用于类型时,能自动被子类继承

常用Spring注解

Spring在支持依赖注入和AOP切面方面,做了很多基于注解的自动化工作。

@Reponsitory

用于数据访问层DAO,定义一个持久层Bean,该注解会自动解析SQLException翻译成通用的异常

@Service

用于业务层,定义一个业务层Bean,是最常用的注解

@Controller

用于WEB层定义MVC控制器

@Compenent

通用意义的组件,以上三者都是组件

自定义注解

有些时候,为了减少重复代码,自动化的做一些事情,需要自定义注解及解释分析。

注解语法

定义

modifiers @interface AnnotationName {
    type elementName1();
    type elementName2() default xxx;
    ...
}

注解元素支持的类型:

  • 基本类型(int, short, long, byte, char, double, float, boolean)
  • String
  • Class
  • enum类型
  • 注解类型
  • 以上类型的数组

使用

@AnnotationName(elementName1=value1, elementName2=value2)

一个项可以使用多个注解,只要它们属于不同的类型即可。

解析注解的例子

支持基于json配置的自动化配置接口的注解@Value

  • Value.java
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)
public @interface Value {
    String value();
}
  • IConfig.java
public interface IConfig {
    @Value("url")
    String dbUrl();

    @Value("pool_size")
    int poolSize();
}
  • ConfigFactory.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;

import com.alibaba.fastjson.JSON;

public class ConfigFactory {

    private ConfigFactory() {}

    public static IConfig create(final String config) {

        final Properties properties = JSON.parseObject(config, Properties.class);

        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {

                final Value value = method.getAnnotation(Value.class);

                if (value == null)
                    return null;

                String property = properties.getProperty(value.value());
                if (property == null)
                    return null;

                final Class<?> returns = method.getReturnType();
                if (returns.isPrimitive()) {
                    if (returns.equals(int.class))
                        return (Integer.valueOf(property));
                    else if (returns.equals(long.class))
                        return (Long.valueOf(property));
                    else if (returns.equals(double.class))
                        return (Double.valueOf(property));
                    else if (returns.equals(float.class))
                        return (Float.valueOf(property));
                    else if (returns.equals(boolean.class))
                        return (Boolean.valueOf(property));
                }

                return property;
            }
        };

        return (IConfig) Proxy.newProxyInstance(
            IConfig.class.getClassLoader(),
            new Class[] { IConfig.class },
            handler);
    }
}
  • MainTest.java
public class MainTest {
    public static void main(String[] args) {

        String strConfig = "{\"url\":\"https://www.suninf.net\", \"pool_size\":\"50\"}";
        IConfig config =  ConfigFactory.create(strConfig);

        String url = config.dbUrl();
        int pool_size = config.poolSize();
    }
}

参考

Comments