Kevin's blog Kevin's blog
首页
  • AI基础
  • RAG技术
  • 提示词工程
  • Wireshark抓包
  • 常见问题
  • 数据库
  • 代码技巧
  • 浏览器
  • 手册教程
  • 技术应用
  • 流程规范
  • github技巧
  • git笔记
  • vpn笔记
  • 知识概念
  • 学习笔记
  • 环境搭建
  • linux&运维
  • 微服务
  • 经验技巧
  • 实用手册
  • arthas常用
  • spring应用
  • javaAgent技术
  • 网站
友情链接
  • 分类
  • 标签
  • 归档

Kevin

你可以迷茫,但不可以虚度
首页
  • AI基础
  • RAG技术
  • 提示词工程
  • Wireshark抓包
  • 常见问题
  • 数据库
  • 代码技巧
  • 浏览器
  • 手册教程
  • 技术应用
  • 流程规范
  • github技巧
  • git笔记
  • vpn笔记
  • 知识概念
  • 学习笔记
  • 环境搭建
  • linux&运维
  • 微服务
  • 经验技巧
  • 实用手册
  • arthas常用
  • spring应用
  • javaAgent技术
  • 网站
友情链接
  • 分类
  • 标签
  • 归档
  • 常见问题

  • 数据库

  • 代码技巧

  • 浏览器

  • spring应用

    • spring常用组件扩展点
      • 常见用法
        • 1. 使用@Configuration类配合@Bean
        • 2. 实现ApplicationListener<ContextRefreshedEvent>
        • 3. 实现CommandLineRunner 或 ApplicationRunner
        • 4. 使用BeanPostProcessor
        • 5. 使用@EventListener
      • 高级用法
        • 1. 使用 ImportBeanDefinitionRegistrar
        • 2. 使用 BeanDefinitionRegistryPostProcessor
        • 3. 使用 FactoryBean 动态创建Bean
        • 4. 结合使用 @Conditional
        • 5. 使用 AspectJ 进行编译时织入
        • 6. 使用 Spring Cloud 的功能
        • 7. 自定义 ClassLoader
        • 8. Spring的 EnvironmentPostProcessor
        • 9. 使用反射技术动态操作Bean
    • spring中的配置文件
  • 使用Java Agent字节码技术扩展
  • 什么是AP,什么是CP,什么是CAP
  • RabbitMq相关
  • ELK查询技巧
  • 性能优化手段
  • 经验技巧
  • spring应用
kevin
2024-04-13
目录

spring常用组件扩展点

# 常见用法

# 1. 使用@Configuration类配合@Bean

通过在配置类中使用@Bean方法,可以在容器启动时执行特定逻辑。这种方式简单直接,适用于大多数初始化逻辑。

@Configuration
public class JobConfig {
    
    @Bean
    public MyJobRegistrar myJobRegistrar(ListableBeanFactory beanFactory) {
        MyJobRegistrar registrar = new MyJobRegistrar(beanFactory);
        serviceMethod();  // 自定义方法,用于处理注解和注册任务
        return registrar;
    }
}
1
2
3
4
5
6
7
8
9
10

# 2. 实现ApplicationListener<ContextRefreshedEvent>

通过监听ContextRefreshedEvent,你可以在Spring容器加载完毕后执行自定义逻辑。这在确保所有的bean都已经创建完成后执行初始化代码时非常有用。

@Component
public class JobRegistrationListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext context = event.getApplicationContext();
        // 执行逻辑
        
    }

    private void registerJobs(ApplicationContext context) {
        // 逻辑处理
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3. 实现CommandLineRunner 或 ApplicationRunner

这两个接口都是在Spring应用程序启动后执行特定代码的方式。CommandLineRunner和ApplicationRunner的不同之处在于接受的参数类型不同。

@Component
public class JobStartupRunner implements CommandLineRunner {

    @Autowired
    private ApplicationContext context;

    @Override
    public void run(String... args) throws Exception {
        // 执行任务注册逻辑
        serviceMethod(context);
    }

    private void registerJobs(ApplicationContext context) {
        // 逻辑处理
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 4. 使用BeanPostProcessor

如果你需要在bean的初始化阶段介入,BeanPostProcessor提供了在bean初始化前后执行操作的能力。这可以用来检查是否有特定的注解并据此做一些操作。

@Component
public class JobAnnotationProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 检查bean上的注解
        checkForJobAnnotation(bean, beanName);
        return bean;
    }

    private void checkForJobAnnotation(Object bean, String beanName) {
        // 注册逻辑
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 5. 使用@EventListener

如果你更喜欢使用注解的方式监听应用事件,@EventListener提供了一种简单的方法来响应不同的事件。

@Component
public class JobEventProcessor {

    @EventListener
    public void handleContextRefresh(ContextRefreshedEvent event) {
        // 执行任务注册逻辑
        ApplicationContext context = event.getApplicationContext();
        serviceMethod(context);
    }

    private void registerJobs(ApplicationContext context) {
        // 逻辑处理
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

每种方法都有其用武之地,具体使用哪种取决于你的具体需求和偏好。考虑到你的需求是在容器启动阶段注册任务,使用ApplicationListener<ContextRefreshedEvent>或CommandLineRunner可能是最直接的方法。

# 高级用法

例如使用 ImportBeanDefinitionRegistrar 和 BeanDefinitionRegistryPostProcessor。这些技术通常被用于高级配置场景,可以在Spring上下文的生命周期的早期介入,允许我们在容器实例化bean之前修改bean定义或动态注册bean。

# 1. 使用 ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar 可以在配置类处理阶段动态注册Bean,这个接口允许编程式的方式控制Bean的注册过程,非常适合处理自定义注解。

public class JobRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 根据条件动态注册bean或者修改已存在的bean定义
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyJobInitializer.class);
        registry.registerBeanDefinition("myJobInitializer", builder.getBeanDefinition());
    }
}

@Configuration
@Import(JobRegistrar.class)
public class JobConfig {
    // 配置类内容
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2. 使用 BeanDefinitionRegistryPostProcessor

这是一个更为强大的工具,可以在容器标准初始化之后、所有bean定义将要被加载,bean实例还未创建前修改bean定义或增加额外的bean定义。

@Component
public class JobBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyJobInitializer.class);
        registry.registerBeanDefinition("myJobInitializer", builder.getBeanDefinition());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 可用于修改Bean属性等后续处理
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3. 使用 FactoryBean 动态创建Bean

FactoryBean是Spring提供的一个接口,通过实现这个接口,可以让你控制bean的实例化过程。这是实现复杂初始化逻辑或者动态代理创建的一种方式。

public class JobFactoryBean implements FactoryBean<JobComponent> {

    @Override
    public JobComponent getObject() throws Exception {
        return new JobComponent(); // 可以实现复杂的初始化逻辑
    }

    @Override
    public Class<?> getObjectType() {
        return JobComponent.class;
    }

    @Override
    public boolean isSingleton() {
        return true; // 根据需要返回 true 或 false
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 4. 结合使用 @Conditional

结合上述技术,使用@Conditional可以根据环境或其他条件动态激活或禁用某些配置,进一步增加配置的灵活性和动态性。

@Conditional(MyCondition.class)
public class ConditionalJobConfig {
    // 根据条件注册Bean
}
1
2
3
4

# 5. 使用 AspectJ 进行编译时织入

AspectJ 是一种与 Spring AOP 兼容的强大的面向切面的编程工具,它支持在编译时进行织入,而不是运行时。这意味着你可以在编译阶段修改字节码,实现非常复杂和强大的功能,而且性能开销比运行时代理小。

// 定义一个切面处理你的自定义注解
@Aspect
public class JobAspect {
    @Before("@annotation(your.custom.annotation.Job)")
    public void beforeJob(JoinPoint joinPoint) {
        // 实现逻辑
    }
}
1
2
3
4
5
6
7
8

# 6. 使用 Spring Cloud 的功能

如果你的应用是微服务架构,可以利用 Spring Cloud 提供的各种功能,如配置管理、服务发现和断路器。通过 Spring Cloud Config,可以动态地管理和注入配置,而不是静态地在应用中配置。

@RefreshScope
@RestController
public class MyController {
    @Value("${some.value}")
    private String value;

    @RequestMapping("/get")
    public String get() {
        return this.value;
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 7. 自定义 ClassLoader

在 Java 中,ClassLoader 负责加载类。通过自定义 ClassLoader,可以在运行时动态地修改或生成类。结合 Spring,你可以控制 Spring Bean 的加载过程,甚至实现热替换部分组件。

public class MyClassLoader extends ClassLoader {
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name.startsWith("my.special.package")) {
            // 自定义加载逻辑
            return generateClass(name);
        }
        return super.loadClass(name, true);
    }

    private Class<?> generateClass(String name) {
        // 生成或修改类的字节码
        return defineClass(name, bytecode, 0, bytecode.length);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 8. Spring的 EnvironmentPostProcessor

EnvironmentPostProcessor 允许在应用程序环境准备好之前自定义设置环境。这个处理器可以用来预处理配置数据,为后续的bean创建提供前置条件。

public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        MutablePropertySources sources = environment.getPropertySources();
        Map<String, Object> myMap = new HashMap<>();
        myMap.put("key", "value");
        sources.addFirst(new MapPropertySource("mySource", myMap));
    }
}
1
2
3
4
5
6
7
8
9

# 9. 使用反射技术动态操作Bean

通过反射API,可以在运行时读取或修改类的私有成员,包括私有字段、方法等,从而实现高度灵活的动态特性。

@Component
public class DynamicBeanModifier {

    @Autowired
    private ApplicationContext context;

    public void modifyBean(String beanName) throws Exception {
        Object bean = context.getBean(beanName);
        Field field = bean.getClass().getDeclaredField("someField");
        field.setAccessible(true);
        field.set(bean, "newValue");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
上次更新: 2024/04/13, 17:38:00
使用xswitch转发浏览器请求本地调试
spring中的配置文件

← 使用xswitch转发浏览器请求本地调试 spring中的配置文件→

最近更新
01
AI是如何学习的
06-03
02
提示词工程实践指南
06-03
03
chatGpt提示原则
06-03
更多文章>
| Copyright © 2022-2025 Kevin | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式