Java注解的使用,实现仿Spring的对象装载

来源:互联网 发布:淘宝虚拟网店取消 编辑:程序博客网 时间:2024/06/05 03:02

Java注解的使用,实现仿Spring的对象装载

看到Spring的注解,相信大家和我一样,都很想知道它怎么工作的,它是怎么实现注入的功能吧。废话就不用多说了,我们直接开始进入正题吧。

实现仿Spring的注解,只需要四步。

1.注解的创建
注解的创建很简单,只需要知道其基本语法就行了。
@interface 用来创建注解
@Retention 用来声明注解生命周期
@Target 用来声明注解适用范围
@Inherited 用来描述注解可引用至注解的类的子类(本文未用到)
@Document 用来指示注解将被文档化。
具体的值可以参考JavaAPI

1.1 创建用于声明bean对象的注解Component.java
package com.test.annotation.test3.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE})//声明该注解用于类、接口等定义时期public @interface Component {    String value() default "";}
1.2 创建依赖注入的注解Bean.java
package com.test.annotation.test3.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)//声明该注解生命周期为运行时,即要被虚拟机识别@Target(ElementType.FIELD)//声明该注解用于字段定义时期public @interface Bean {    String value() default "";}
1.3 创建用于注入值的注解Value.java:
package com.test.annotation.test3.annotation;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Value {    String value() default "";}

上文提到两个类RetentionPolicy和ElementType,它们分别是帮助注解描述生命周期和作用范围,想要详细了解,请参考JavaAPI

2.业务逻辑的实现

2.1 创建模型层Model.java
package com.test.annotation.test3.content;import com.test.annotation.test3.annotation.Component;import com.test.annotation.test3.annotation.Value;@Component("model")public class Model {    @Value("张三")    public String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}
2.2 创建Dao层Dao.java:
package com.test.annotation.test3.content;import com.test.annotation.test3.annotation.Bean;import com.test.annotation.test3.annotation.Component;@Component("dao")public class Dao {    @Bean("model")    public Model model;    @Override    public String toString() {        String text="name:"+model.getName();        return text;    }}
2.3 创建service层Service.java:
package com.test.annotation.test3.content;import com.test.annotation.test3.annotation.Bean;import com.test.annotation.test3.annotation.Component;@Component("service")public class Service {    @Bean("dao")    public Dao dao;    @Override    public String toString() {        return dao.toString();    }}

3.创建对象的注入工具(关键):

package com.test.annotation.test3.content;import java.io.File;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;import com.test.annotation.test3.annotation.Bean;import com.test.annotation.test3.annotation.Component;import com.test.annotation.test3.annotation.Value;public class AnnotationUtil {    public Map<String, Object> maps = new HashMap<String, Object>();    /**     * 初始化注解     * @param packageName 搜索包路径名     * @throws Exception     */    public void initAnnotation(String packageName) throws Exception {        packageName += ".";        byte[] packagePathForByte = packageName.getBytes();        //把包路径转化为文件路径        for (int i = 0; i < packagePathForByte.length; i++) {            if (packagePathForByte[i] == '.') {                packagePathForByte[i] = File.separator.getBytes()[0];            }        }        String packagePath = new String(packagePathForByte);        //这里限制了搜索的路径的位置是基于源码的src目录下的类路径开始,需要根据实际需要更改        File root = new File(System.getProperty("user.dir") + File.separator + "src" + File.separator + packagePath                + File.separator);        loopClazz(root, packageName);        for (String key : maps.keySet()) {            Object object=maps.get(key);            inject(object);        }    }    /**     * 循环遍历文件夹下的类     * @param folder 搜索的类的路径     * @param packageName 包名(用于创建对象)     * @throws Exception     */    private void loopClazz(File folder, String packageName) throws Exception {        File[] files = folder.listFiles();        for (int fileIndex = 0; fileIndex < files.length; fileIndex++) {            File file = files[fileIndex];            if (file.isDirectory()) {                loopClazz(file, packageName + file.getName() + ".");            } else {                initClazz(file.getName(), packageName);            }        }    }    /**     * 实现对注解的类的初始化     * @param filename java类的名称     * @param packageName 包的名称     */    private void initClazz(String filename, String packageName) {        try {            //用于除去".java"的后缀            String name = filename.substring(0, filename.length() - 5);            Object obj=Class.forName(packageName + name).newInstance();//通过类名加载对象,并创建对象是实例            Class clazz = obj.getClass();            //判断类是否被Component注解            if (clazz.isAnnotationPresent(Component.class)) {                Component component = (Component) clazz.getAnnotation(Component.class);//获取到Component注解                maps.put(component.value(), obj);            }        } catch (Exception e) {            System.out.println("exception = " + e.getLocalizedMessage());        }    }    /**     * 对对象进行装配     * @param object 装配的目标     */    public <T> void inject(T object) {        try {            Class clazz = object.getClass();            Field[] fields = clazz.getDeclaredFields();//获取参数列表            for (Field field : fields) {                //如果是Bean注解,就获取map中的对象,装配到目标对象中                if (field.isAnnotationPresent(Bean.class)) {                    Bean bean = field.getAnnotation(Bean.class);                    field.set(object, maps.get(bean.value()));                }                //如果是Value注解,就获取注解的值,装配到目标对象中                else if (field.isAnnotationPresent(Value.class)) {                    Value value = field.getAnnotation(Value.class);                    field.set(object, value.value());                }            }        } catch (Exception e) {            System.out.println("exception = " + e.getLocalizedMessage());        }    }}

4.测试代码的实现:

package com.test.annotation.test3.content;public class Action {    public static void main(String[] args) {        Service service=new Service();        try {            AnnotationUtil util=new AnnotationUtil();            util.initAnnotation("com.test.annotation.test3.content");//初始化注解程序,类似Spring的包搜索            util.inject(service);//装载对象            System.out.println(service.toString());        } catch (Exception e) {            e.printStackTrace();        }    }}

以上只是简单的实现了注入功能,设计比较简单,主要用于学习注解,如果有什么意见或者建议,欢迎探讨,如果有什么疑问急需要解决,可以发送邮件至我的邮箱1129115956@qq.com。

0 0
原创粉丝点击