Java Spring Boot VS .NetCore (八) Java 注解 vs .NetCore Attribute

和自甴很熟 提交于 2020-12-17 08:28:45

继续前面的章节,这里我介绍下注解,其实Java注解跟.NetCore的特性标签类似,下面我们通过代码来说明

Java自定义注解

首先我先说下Java注解需要使用的注解

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented

Taget:指定注解在什么地方生效,作用于什么对象上,参数很多这里把源码拉出来了,每一个的意思就不过多介绍,一看就明白

public enum ElementType {
    /** 类、接口(包括注释类型)或枚举声明 */
    TYPE,

    /** 字段声明(包括枚举常量) */
    FIELD,

    /** 方法声明 */
    METHOD,

    /** 形式参数声明 */
    PARAMETER,

    /** 构造函数声明 */
    CONSTRUCTOR,

    /** 局部变量声明 */
    LOCAL_VARIABLE,

    /** 注释类型声明 */
    ANNOTATION_TYPE,

    /** 程序包声明 */
    PACKAGE,

    /**
     * 类型参数声明
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * 使用类型
     *
     * @since 1.8
     */
    TYPE_USE
}
 
public enum RetentionPolicy {
    /**
     注解将被编译器丢弃
     */
    SOURCE,

    /**
     注解将由编译器记录在类文件中,但在运行时不需要由VM保留。这是默认的行为。
     */
    CLASS,

    /**
    注解将由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射读取当前注解。*/
    RUNTIME
}
 
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
/*
注解表明这个注解应该被 javadoc工具记录
*/
}
 

下面就来模拟一个自定义的注解,同时简单并模拟MyBatis中的像如下写法,解析下面代码的实现原理

@Select("SELECT username,email,newname,nick_name FROM user_model")
    @Results({
            @Result(property = "username",  column = "username"),
            @Result(property = "email",  column = "email"),
            @Result(property = "newname",  column = "newname"),
            @Result(property = "nickName", column = "nick_name")
    })
    List<UserModel> getAll();
 

这里定义一个自定义的注解接口 代码如下,注解要作用于方法上 

Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomSelect {
String Sql() default "";
}
 

这一步也非常简单,定义一个操作接口,使用自定义的注解,添加好相关的Sql语句

public interface ReflectorDao {

    @CustomSelect(Sql = "select * from user_model where id=1")
    int InsertModel();
}

接下来就是怎么使用了,当然这里还是要用到反射 ,这里我添加了一个测试方法,里面模拟实现了一个JDBC的操作方法

 @Test
    public  void  testReflectorDao() throws Exception {
        Class<?> c=  ReflectorDao.class;
        Method method=c.getMethod("InsertModel");
        CustomSelect  customSelect=method.getAnnotation(CustomSelect.class);
        String strsql= customSelect.Sql();
        System.out.print(strsql+"\r\n");
        //调用JDBC完成操作
        JDBCHelper.ExcuteQuery(strsql);

    }
 

这里反射里面的方法就不特殊说明了,这里说下 获取注解的方法把,如下

//    // 获取某个类型的注解
//    public <A extends Annotation> A getAnnotation(Class<A> annotationClass);
//    // 获取所有注解(包括父类中被Inherited修饰的注解)
//    public Annotation[] getAnnotations();
//    // 获取声明的注解(但是不包括父类中被Inherited修饰的注解)
//    public Annotation[] getDeclaredAnnotations();
//    // 判断某个对象上是否被某个注解进行标注
//    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
//
//    // 获取某个类声明的所有字段
//    public Field[] getDeclaredFields() throws SecurityException;
//    // 获取某个方法
//    public Method getMethod(String name, Class<?>... parameterTypes);
 

执行下单元测试: OK

.NetCore Attribute

Java中有的 .NetCore一样能实现,这里就要介绍.NetCore总的特性了,就是Attribute类,怎么来使用这个呢?不要急,通过带来是解释,自定义的特性需要继承Attribute类,且类名可以以Attribute结尾,这样在使用的时候就可以通过前面的名称来写,代码如下

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
    public class CustomAttribute : Attribute
    {
        public string Sql { get; set; }

    }
 

看到这里,就有一种熟悉感,看下源码,这里什么Class 等等更Java用法一样标识该特性作用于什么对象上,AllowMultiple :标识是否可以指定多次,同一个对象上多次使用特性,Inherited:当前特性是否可以被继承

//
    // 摘要:
    //     Specifies the application elements on which it is valid to apply an attribute.
    [Flags]
    public enum AttributeTargets
    {
        //
        // 摘要:
        //     Attribute can be applied to an assembly.
        Assembly = 1,
        //
        // 摘要:
        //     Attribute can be applied to a module.
        Module = 2,
        //
        // 摘要:
        //     Attribute can be applied to a class.
        Class = 4,
        //
        // 摘要:
        //     Attribute can be applied to a structure; that is, a value type.
        Struct = 8,
        //
        // 摘要:
        //     Attribute can be applied to an enumeration.
        Enum = 16,
        //
        // 摘要:
        //     Attribute can be applied to a constructor.
        Constructor = 32,
        //
        // 摘要:
        //     Attribute can be applied to a method.
        Method = 64,
        //
        // 摘要:
        //     Attribute can be applied to a property.
        Property = 128,
        //
        // 摘要:
        //     Attribute can be applied to a field.
        Field = 256,
        //
        // 摘要:
        //     Attribute can be applied to an event.
        Event = 512,
        //
        // 摘要:
        //     Attribute can be applied to an interface.
        Interface = 1024,
        //
        // 摘要:
        //     Attribute can be applied to a parameter.
        Parameter = 2048,
        //
        // 摘要:
        //     Attribute can be applied to a delegate.
        Delegate = 4096,
        //
        // 摘要:
        //     Attribute can be applied to a return value.
        ReturnValue = 8192,
        //
        // 摘要:
        //     Attribute can be applied to a generic parameter.
        GenericParameter = 16384,
        //
        // 摘要:
        //     Attribute can be applied to any application element.
        All = 32767
    }
 

下面我们同样用接口来实现,代码如下,前面说了 自定义属性已Attribute结尾的类名,写的时候直接写Custom

public interface RelactorDao
    {

        [Custom(Sql = "select * from user_model where id=1")]
        void InsertModel();

    }
 

这里我写一个测试类是看下,由于时间的关系,这里就不写SqlHelper 来执行了,输入下Sql就行了,这个跟Java一样需要使用反射,思想一样,只是使用方法名称不同而已,具体的方法就不做介绍..有兴趣自己了解下

public class TestClass
    {
        public void TestMethod()
        {
            var type = typeof(RelactorDao);
            MethodInfo methodInfo= type.GetMethod("InsertModel");
            var atrrs = methodInfo.GetCustomAttributes(typeof(CustomAttribute), false) as CustomAttribute[];
            var strSql = atrrs.First().Sql;
            //当然这里也可以执行
            Console.WriteLine(strSql);
        }
    }
 

接下来我们在看下执行效果 OK

 

 总结

这里只是简单的模拟下,其实要实现MyBatis中的注解的功能,其实还需要其他的知识,面向切面编程的技术AOP

Java中的 @Aspect 注解 ,.NetCore 可以通过动态代理来实现,但是反过来想下,.NetCore中一样可以实现类似于MyBait一样使用方式的ORM框架,可能.NetCore中考虑到大量应用反射会导致性能问题

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!