思尐-ChatGPT:你不懂可以来问我啊!

简介: 思尐-ChatGPT:你不懂可以来问我啊!

前言


Hello,大家好,我是java小面。不知道大家有没有自己实现过一个注解来替换Spring原有注解的经历,有人说Spring不是有注解给你用吗?干嘛还要特地的去实现一个来替换呢?

我们这次去请教ChatGPT如何写这么一段代码

只是可惜,它似乎不太能理解我的需求,还是自己来吧!

关于这个需求,小面当然不是闲得慌,我们做业务功能开发的时候,往往只懂得它该怎么用,却不知道它为什么可以这么用,它具体又是怎样的一个运行机制?

而当我们了解了它的一个机制后,不仅保持住了对技术专研的热情,还收获了成就感,让我们在技术的这条路上越走越远。

如何自定义依赖注入注解?

  1. 基于AutowiredAnnotationBeanPostProcessor实现
  2. 自定义实现
  1. InjectedElement
  2. InjectionMetadata
  3. InstantiationAwareBeanPostProcessor
  4. MergedBeanDefinitionPostProcessor
  5. 生命周期处理
  6. 元数据

这次我们拿最常见的一个注解进行开发。

举个例子

一、copy注解

这是一个大家都常用的注解

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
   /**
    * Declares whether the annotated dependency is required.
    * <p>Defaults to {@code true}.
    */
   boolean required() default true;
}

@Autowired最常用于依赖注入,但是大家都知道,注解是无法拓展的,如果大家想要拓展,唯一的方法就是copy一份一模一样的取代掉它的使用。

比如我重新定义一个Autowired注解且把它用于依赖注入中。

我们给他命名 MyAutowired

/**
 * 自定义注解
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MyAutowired {
    /**
     * Declares whether the annotated dependency is required.
     * <p>Defaults to {@code true}.
     */
    boolean required() default true;
}

其他的和@Autowired一模一样,区别在于public上面把 Autowired注解标注上了。

因为Autowired本身拥有ElementType.ANNOTATION_TYPE就说明它允许被使用在注解上面

测试Demo

package org.example.definition;
import org.example.pojo.MyAutowired;
import org.example.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author Java面试教程
 * @date 2022-12-18 21:14
 */
@Configuration
public class Demo {
    @Bean
    public User User(){
        return new  User(1,"Java面试教程");
    }
    @Autowired
    private User user;
    @MyAutowired
    private User myUser;
    public static void main(String[] args)
    {
        //创建BeanFactory容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册当前类,主要目的是获取@Bean
        applicationContext.register(Demo.class);
        //启动应用上下文
        applicationContext.refresh();
        Demo bean = applicationContext.getBean(Demo.class);
        System.out.println("user对象:"+bean.user);
        System.out.println("myUser对象:"+bean.myUser);
        applicationContext.close();
    }
}

结果

Connected to the target VM, address: '127.0.0.1:65300', transport: 'socket'
user对象:User{id=1, name='Java面试教程'}
myUser对象:User{id=1, name='Java面试教程'}
Disconnected from the target VM, address: '127.0.0.1:65300', transport: 'socket'

说明拥有ElementType.ANNOTATION_TYPE的元标注可以通过这种方式来拓展开发。

二、自定义注解

接下来我们讲一下,用AutowiredAnnotationBeanPostProcessor怎么去实现自定义依赖注入注解

首先还是定义一个注解,这个注解不包含其他注解

/**
 * 自定义依赖注入注解
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomAutowired {
}

然后重新实现 AutowiredAnnotationBeanPostProcessor 的bean对象

@Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor(){
    AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
    Set<Class<? extends Annotation > > types = new LinkedHashSet<>(Arrays.asList(Autowired.class, MyAutowired.class, CustomAutowired.class));
    beanPostProcessor.setAutowiredAnnotationTypes(types);
    return beanPostProcessor;
}

AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME 是Autowired默认的Bean名称,所以我们重新,且把自己定义的CustomAutowired注入进去,那么我们之后使用@CustomAutowired的时候它就可以达到和Autowired一样的效果了。

Set<Class<? extends Annotation > > types = new LinkedHashSet<>(Arrays.asList(Autowired.class, MyAutowired.class, CustomAutowired.class));
    beanPostProcessor.setAutowiredAnnotationTypes(types);

如果types里只有CustomAutowired.class,没有Autowired.class, MyAutowired.class,那么原本使用@Autowired和@MyAutowired的对象,就只会拿到null,因为你重新覆盖的值里面没有他们。那么他们就不被归类到依赖注入的用法里面了。

感兴趣的可以自己试试运行,随便找一个类替换掉User就能执行了。

测试Demo

import static org.springframework.context.annotation.AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME;
/**
 * @author Java面试教程
 * @date 2022-12-26 21:14
 */
@Configuration
public class Demo {
    @Bean
    public User User(){
        return new User(1,"Java面试教程");
    }
    @Autowired
    private User user;
    @CustomAutowired
    private User customAutowiredUser;
    @MyAutowired
    private User myUser;
    @Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
    public static AutowiredAnnotationBeanPostProcessor beanPostProcessor(){
        AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
        Set<Class<? extends Annotation > > types =
                new LinkedHashSet<>(Arrays.asList(Autowired.class, MyAutowired.class, CustomAutowired.class));
        beanPostProcessor.setAutowiredAnnotationTypes(types);
        return beanPostProcessor;
    }
    public static void main(String[] args)
    {
        //创建BeanFactory容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册当前类,主要目的是获取@Bean
        applicationContext.register(Demo.class);
        //启动应用上下文
        applicationContext.refresh();
        Demo bean = applicationContext.getBean(Demo.class);
        System.out.println("user对象:"+bean.user);
        System.out.println("myUser对象:"+bean.myUser);
        System.out.println("自定义对象:"+bean.customAutowiredUser);
        applicationContext.close();
    }
}

结果

Connected to the target VM, address: '127.0.0.1:52324', transport: 'socket'
user对象:User{id=1, name='Java面试教程'}
myUser对象:User{id=1, name='Java面试教程'}
自定义对象:User{id=1, name='Java面试教程'}
Disconnected from the target VM, address: '127.0.0.1:52324', transport: 'socket'

结束语

我们刚刚通过了 拓展@Autowired注解 以及 复用AutowiredAnnotationBeanPostProcessor这个API 两种方式来实现替代@Autowired注解,虽然内容简单,但是却通过了AutowiredAnnotationBeanPostProcessor向大家揭晓了为什么Autowired可以达到依赖注入的原因。

相关文章
|
9月前
|
机器学习/深度学习 人工智能 自然语言处理
ChatGPT 和文心一言哪个更好用?
ChatGPT 和文心一言哪个更好用?
183 1
|
自然语言处理 iOS开发
ChatGPT出圈,不在于技术牛
ChatGPT出圈,不在于技术牛
81 0
|
3月前
|
人工智能 自然语言处理 数据库
RAG 技术:让 AI 从 “书呆子” 变身 “开卷小天才”!
鳄叔介绍了RAG(检索增强生成)技术,这是一种让AI既能查资料又能灵活作答的方法,如同“开卷考试”的学霸。RAG结合了检索能力和生成能力,使AI能够实时获取最新信息,提供更专业、精准的回答,广泛应用于企业客服、法律咨询、医疗诊断和教育等领域。
|
6月前
|
人工智能 自然语言处理 小程序
【AI】Gemini:听说GPT-4你小子挺厉害
谷歌推出新AI模型Gemini Pro,支持中文并具备多模态处理能力,涵盖文本、图像、音频、视频和代码。本文通过五个问题对比Gemini Pro与ChatGPT-4的表现,包括绘画、数学题解答、成语解释、天气查询及奥运冠军名单。结果显示两者各有优势,Gemini Pro在成语解释和天气查询方面略胜一筹,而ChatGPT-4在绘画方面表现更好
79 0
【AI】Gemini:听说GPT-4你小子挺厉害
|
9月前
|
人工智能 测试技术 API
Claude 3被玩出自我意识了吗?
【2月更文挑战第16天】Claude 3被玩出自我意识了吗?
167 13
Claude 3被玩出自我意识了吗?
|
9月前
|
人工智能 机器人
【好玩AI】【Prompt】情人节了,用GPT写个【骂醒恋爱脑】的机器人跟自己对话吧
【好玩AI】【Prompt】情人节了,用GPT写个【骂醒恋爱脑】的机器人跟自己对话吧
335 0
|
机器学习/深度学习 人工智能 自然语言处理
chatGPT爆火,什么时候中国能有自己的“ChatGPT“
chatGPT爆火,什么时候中国能有自己的“ChatGPT“
|
机器学习/深度学习 人工智能 自然语言处理
3 千字浅谈:AI 之巅,ChatGPT 之背后
AI 发展经历多个里程碑,最早可以追溯到 1950 年代,早期人们开始探索 AI 即人工智能的概念,后来就开发了一些早期的处理语言,比如 ELIZA;
|
机器学习/深度学习 人工智能 自然语言处理
不要叫我程序员,我是「AI工程师」,马斯克:开始卷自然语言编程
不要叫我程序员,我是「AI工程师」,马斯克:开始卷自然语言编程
187 0
|
机器学习/深度学习 人工智能 自然语言处理
《花雕学AI》21:脑筋急转弯---ChatGPT能够灵活运用逻辑推理和创造性思维吗?
随着人工智能技术的不断发展和成熟,ChatGPT在未来还有很大的应用前景。例如,在教育领域,ChatGPT可以被应用于编写智力游戏、脑力训练等课程内容,从而帮助学生提高思维能力和语言表达能力。同时,在娱乐行业,ChatGPT也可以被用于开发各种趣味游戏,满足人们的娱乐需求。 然而,我们也必须承认,ChatGPT在解决脑筋急转弯问题上仍存在一些挑战和限制。例如,在处理一些复杂的双关语和玩味语言时,模型的效果可能会受到影响,需要不断地优化和改进。
430 0
《花雕学AI》21:脑筋急转弯---ChatGPT能够灵活运用逻辑推理和创造性思维吗?