Java注解依赖注入简单实现

本文详细介绍了如何在Spring Boot中使用自定义注解进行对象的依赖注入,包括注解的定义、元注解的作用和实际应用示例,展示了如何通过注解标记对象并进行自动识别和处理。

       这里先说一下,部分同学接触注解可能都是在spring相关学习和使用中,但其实注解本身和spring并没有什么必然关系,注解是java本身的具有的功能,在重写对象方法的时候大家应该都见过,只是可能并没有在意。注解的本质我个人理解就是一种轻量级的特殊接口,被以注解的形式使用,直接套在对象的头上,给对象增加一个特殊标识,方便在反射中进行识别。

       所以这里大家要明白一点,spring或者其相关框架springboot这样的,都只会自动识别和处理自身设定的注解,我们自己写的注解只能我们自己来进行处理。不要抄了一个注解改了个名字,然后使用发现没有效果觉得奇怪。注解只能标识,本身没有处理能力。不要觉得我这是废话,因为我就见过不止一个人在学习注解的时候这么干。

       首先说一下注解的基本样式:

import java.lang.annotation.*;
//注解适用范围
@Target({ElementType.TYPE})
//注解保留策略,编译前,编译后,运行时(默认为编译后)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotaionBean {}

       有人会问,上面四个注解是啥?可以不要吗?可以不写,因为他们都是有默认值的,但是要看你这个注解是打算怎么用,比如我这个是用来标记特定对象,那么如果不加@Retention(RetentionPolicy.RUNTIME) 这句,在程序启动后,运行中通过反射就无法判断是那个对象被标识,因为在运行时注解已经被抛弃了。

        这几个注解都是java定义的元注解,可以理解成java对注解进行的规范要求,是注解本身的属性。@Target声明注解的使用范围,是对象头,还是属性或者函数和其他位置。@Retention声明注解保留策略,也可以理解为生命周期。@Documented声明该注解应该被标注为对象成员公共API,可以被javadoc等工具文档化。@Inherited声明该注解是否被对象的子类继承。

       下面就用最基本的依赖注入来说明一下自定义注解,为了方便我使用了springboot生成项目,这样可以忽略对象生成的过程。下面先是注入用的注解:

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired {
    String value() default "";
}

       上面的MyAnnotaionBean是用来标记被添加了注解的对象,避免轮询全部对象,既然标记了,那当然要做一下记录,于是写了一个静态集合用来记录被标记的对象:

public class MyAnnotationClassName {
    public static List<String> classNames = new ArrayList<String>();
}

       下面我们在springboot的启动main函数中增加相关代码,为了省略对象实例化部分,我把对象加了spring注解自动实例化,只是对注入的部分进行了自定义:

public static void main(String[] args) {
   //获取容器入口
   ConfigurableApplicationContext cac = SpringApplication.run(MyStydySpringbootDemoApplication.class, args);
   //判断加特定注解的对象数量
   if(MyAnnotationClassName.classNames.size() > 0){
      for(String className : MyAnnotationClassName.classNames){
         //从容器中提取对象
         Object bean = cac.getBean(className);
         //属性
         Field[] fld = bean.getClass().getDeclaredFields();
         for(Field fs : fld){
            //判断属性注解
            if(!fs.isAnnotationPresent(MyAutowired.class)) { continue; }
            MyAutowired myAuto = fs.getAnnotation(MyAutowired.class);
            //获取注解属性值
            String perpam = myAuto.value();
            if(perpam == null || "".equals(perpam.trim())) {
               //注解无属性值则直接使用属性名称
               perpam = fs.getName();
            }
            //给参数赋值
            try {
               //private属性需要设置后才能注入
               fs.setAccessible(true);
               System.out.println("MyAutowired注入"+perpam);
               //注入
               fs.set(bean, cac.getBean(perpam));
            } catch (IllegalArgumentException e) {
               e.printStackTrace();
            } catch (IllegalAccessException e) {
               e.printStackTrace();
            }
         }
      }
   }
}

       为了给MyAnnotationClassName中写入值,我偷了下懒,直接利用Processor在bean初始化时进行记录

@Component
public class MyProcessor  implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean.getClass().isAnnotationPresent(MyAnnotaionBean.class)){
            MyAnnotationClassName.classNames.add(beanName);
        }
        return bean;
    }

       最后就是直接的使用了:

@MyAnnotaionBean
@RestController
public class MyController {
    @MyAutowired(value = "userDaoMySql")
    private IUserDao userDao;
    @MyAutowired(value = "UserInfo")
    private UserInfo uinfo;

    @RequestMapping("/user")
    public String getUser(@RequestParam Integer userid){
        UserDTO ud = userDao.findUserById(userid);
        return ud.getUserName();
    }

    @RequestMapping("/userAll")
    public String getAllUser(){
        List<UserDTO> userDTO = userDao.getAllUser();
        JSONPObject jo = new JSONPObject("",userDTO);
        return jo.toString();
    }

    @RequestMapping("/skill")
    public String getSkill(){
        return uinfo.getUserName();
    }
}

       之后我们来看看效果。

        从运行来看注入操作已经进行了,那么看前端返回。

       返回正确,注入成功了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值