java注解的理解与运用

硅谷探秘者 3381 0 2

在用各种框架的时候,注解是几乎都会遇到的,那么他的原理是怎么样的呢!来探究一下

1.我们用过很多注解比如下面的 jdk自带的注解

@Override 表示覆盖或重写父类的方法;

@Deprecated 表示该方法已经过时了。(当方法或是类上面有@Deprecated注解时,说明该方法或是类都已经过期不能再用,但不影响以前项目使用,提醒你新替代待的方法或是类。如果程序员不小心使用了它的元素,那么编译器会发出警告信息。

@SuppressWarnings 表示忽略指定警告,比如@Suppvisewarnings("Deprecation")

2.注解的分类

        按运行机制(注解存在于程序的那个阶段)将注解分为三类:源码注解(只在源码存在,编译成class文件注解就不存在了)、编译注解(在class文件中也存在)、运行时注解(在运行阶段仍然起作用)

        按照来源来分,有如下三类:
1:JDK自带的注解(Java目前只内置了三种标准注解:@Override、@Deprecated、@SuppressWarnings,以及四种元注解:@Target、@Retention、@Documented、@Inherited)
2:第三方的注解——这一类注解是我们接触最多和作用最大的一类
3:自定义注解——也可以看作是我们编写的注解,其他的都是他人编写注解

        按照功能来分的,还有,元注解——注解的注解。

元注解是指注解的注解,包括@Retention @Target @Document @Inherited四种。


@Target

表示该注解可以用于什么地方,可能的ElementType参数有:

CONSTRUCTOR:构造器的声明

FIELD:域声明(包括enum实例)

LOCAL_VARIABLE:局部变量声明

METHOD:方法声明

PACKAGE:包声明

PARAMETER:参数声明

TYPE:类、接口(包括注解类型)或enum声明

@Retention

表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

SOURCE:注解将被编译器丢弃

CLASS:注解在class文件中可用,但会被VM丢弃

RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。

@Document

将注解包含在Javadoc中

@Inherited

允许子类继承父类中的注解

3.自定义注解

package club.jiajiajia.test;

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    public String a() default "aaa";
    public String b();
}

4.使用注解

package club.jiajiajia.test;
import club.jiajiajia.annbuliding.MyBeanFactory;
import club.jiajiajia.custom.Controller;
@MyAnnotation(b="bbb")
public class TestAnn {

}

5.注解的解析(用到了反射)

public class Main {

    public static void main(String[] args) {
        Class clazz = TestAnn.class;//获取带注解类的class对象
        //获取类上面的注解
        MyAnnotation ann=(MyAnnotation)clazz.getAnnotation(MyAnnotation.class);
        //得到了注解,我们就可以做一些事情了
        System.out.println(ann.a());
        System.out.println(ann.b());
    }
}


6.那么如果理解了注解的原理,那我们就可以大胆的想象一下spring的ioc容器时如何通过注解来扫描类和创建对象的了,做一个大胆的实验(前无古人,后无来者)

首先我们创建两个注解

AutoBuliding模拟spring中的Autowire

package club.jiajiajia.annbuliding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoBuliding {
}

Klasses模拟spring中的Controller

package club.jiajiajia.annbuliding;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Klasses {
}

创建一个扫描文件下的类的类

package club.jiajiajia.annbuliding;

import club.jiajiajia.Main;
import org.junit.Test;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 扫描指定目录下的类
 */
public class Scanning {
    private List<String> classPaths = new ArrayList<String>();
    private Set<Class<?>>  clazz =new HashSet<>();
    private String basePack;
    private String classpath;

    public Scanning(String basicPathes){
        this.basePack = basicPathes.replace(".", File.separator);
        classpath = MyBeanFactory.class.getResource("/").getPath();
        try {
            searchClass();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public void searchClass() throws ClassNotFoundException {
        doPath(new File(classpath + basePack));
        Class cls=null;
        for (String s : classPaths) {
            s = s.replace(classpath.replace("/","\\")
                    .replaceFirst("\\\\",""),"")
                    .replace("\\",".")
                    .replace(".class","");
            cls = Class.forName(s);
            clazz.add(cls);
        }
    }
    private void doPath(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f1 : files) {
                doPath(f1);
            }
        } else {
            if (file.getName().endsWith(".class")) {
                classPaths.add(file.getPath());
            }
        }
    }

    public Set<Class<?>> getClazz() {
        return clazz;
    }
}

创建一个解析注解的类(其中用到了一个Controller类,比如Controller类是从文件中扫描出来的)模拟 Spring 的applicationcontext

package club.jiajiajia.annbuliding;
import club.jiajiajia.custom.Controller;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/***
 * 自动装配对象
 */
public class MyBeanFactory {
    Map<String,Object> map=new HashMap();
    public MyBeanFactory(String path){
        Scanning s=new Scanning(path);
        Set<Class<?>> c= s.getClazz();
        for(Class<?> sc:c){
            buding(sc);
        }
    }
    public void buding(Class c){
        Klasses k=(Klasses)c.getAnnotation(Klasses.class);
        if(k!=null){//类上有注解
            if(!map.containsKey(c.getName())){//map里面没有包含类
                System.out.println("创建类");
                try {
                    Object o = c.newInstance();
                    map.put(c.getName(),o);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {//遍历类的所有的属性
                AutoBuliding a=field.getAnnotation(AutoBuliding.class);
                if(a!=null){//如果属性有注解
                    field.setAccessible(true);
                    if(map.containsKey(field.getGenericType().getTypeName())){//如果map里面有这个类
                        try {
                            field.set( map.get(c.getName()),map.get(field.getGenericType().getTypeName()));
                            //注入属性
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }else{
                        try {
                            buding(Class.forName(field.getGenericType().getTypeName()));
                            field.set( map.get(c.getName()),map.get(field.getGenericType().getTypeName()));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    public Object getBean(Class c){
        return map.get(c.getName());
    }
}

然后创建三个类,模拟 controller,service , dao

package club.jiajiajia.custom;

import club.jiajiajia.annbuliding.AutoBuliding;
import club.jiajiajia.annbuliding.Klasses;

@Klasses
public class Controller {

    @AutoBuliding
    private Service service;

    public void test(){
        System.out.println("经过controller");
        System.out.println(service.service());
    }
}
package club.jiajiajia.custom;

import club.jiajiajia.annbuliding.AutoBuliding;
import club.jiajiajia.annbuliding.Klasses;

@Klasses
public class Service {

    @AutoBuliding
    private Dao dao;

    public String service(){
        System.out.println("经过serviice");
        return dao.dao();
    }
}
package club.jiajiajia.custom;

import club.jiajiajia.annbuliding.Klasses;

@Klasses
public class Dao {
    public String dao(){
        System.out.println("经过dao");
        return "查出数据";
    }
}

测试类

package club.jiajiajia;
import club.jiajiajia.annbuliding.MyBeanFactory;
import club.jiajiajia.custom.Controller;
public class Main6 {

    public static void main(String[] args) {
        Controller c=(Controller)new MyBeanFactory("club.jiajiajia.custom").getBean(Controller.class);
        c.test();
    }
}

那么对外的表现形式就是

QQ截图20190116000143.png


是不是很神奇,我们并没有手动创建对象,但是对象确是存在的,而且完美的注入到了对应的地方。



评论区
请写下您的评论...
暂无评论...
猜你喜欢
算法基础 1055 1、@SpringBootApplication这是SpringBoot最最最核心在SpringBoot主类上,标识这是一个SpringBoot应来开启SpringBoot各项能力
spring/springmvc 1321 @Component:将普通pojo实例化到ioc容器 @AutoConfigureBefore(A.class):加此bean会在A加载之前加载 @AutoConfigureAfter
java虚拟机(jvm) 5103 常是按需加载,即第一次使该类时才加载。由于有了类加载器,Java行时系统不需要知道文件文件系统。学习类加载器时,掌握Java委派概念很重要。1.类加载过程:2.类生命周期:加载:"加载"是"
java基础 1490 java并发编程-CAS算法1.什么是cas算法?CAS:CompareandSwap,即比较再交换。jdk5增加了并发包java.util.concurrent.*,其下面类使CAS算法实
框架 1374 能手动去写这些逻辑。最终把它封装成一个可以方便直接转换成对象得工具类。首先明确我们得目是什么现有一个excel表,如下图:现需要把excel表中每一行都封装在一个java对象中,当然如果poia
java虚拟机(jvm) 1438 硬件效率一致性在正式讲Java虚拟机并发相关知识之前,我们先花费一点时间去了一下物计算机中并发问题,物机遇到并发问题虚拟机中情况有不少相似之处,物机对并发方案对于虚拟机
框架 5282 springmvc项目中,如一个项目页面调另一个项目接口会产生跨域问题403。对于一个接口而言很好决跨域问题,springmvc中只需要在接口上加一个。@CrossOrigin
mqtt协议 1348 )允许户动态创建主题,零维成本;(4)把传输量降到最低以提高传输效率;(5)把低带宽、高延迟、不稳定网络等因素考虑在内;(6)支持连续会话控制;(7)客户端计算能力可能很低;(8)提供服务
归档
2018-11  12 2018-12  33 2019-01  28 2019-02  28 2019-03  32 2019-04  27 2019-05  33 2019-06  6 2019-07  12 2019-08  12 2019-09  21 2019-10  8 2019-11  15 2019-12  25 2020-01  9 2020-02  5 2020-03  16 2020-04  4 2020-06  1 2020-07  7 2020-08  13 2020-09  9 2020-10  5 2020-12  3 2021-01  1 2021-02  5 2021-03  7 2021-04  4 2021-05  4 2021-06  1 2021-07  7 2021-08  2 2021-09  8 2021-10  9 2021-11  16 2021-12  14 2022-01  7 2022-05  1 2022-08  3 2022-09  2 2022-10  2 2022-12  5 2023-01  3 2023-02  1 2023-03  4 2023-04  2 2023-06  3 2023-07  4 2023-08  1 2023-10  1 2024-02  1 2024-03  1 2024-04  1
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议 keepalived minio mysql ensp 网络基础 xxl-job rabbitmq haproxy srs 音视频 webrtc javascript
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。