文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何掌握Spring

2024-04-02 19:55

关注

这篇文章主要讲解了“如何掌握Spring”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何掌握Spring”吧!

Spring 是一个控制反转依赖管理的容器,作为 Java Web 的开发人员,基本没有不熟悉 Spring 技术栈的,尽管在依赖注入领域,Java  Web 领域不乏其他优秀的框架,如 google 开源的依赖管理框架 guice,如 Jersey web 框架等。但 Spring 已经是 Java Web  领域使用最多,应用最广泛的 Java 框架。

此文将专注讲解如何在 Spring 容器启动时实现我们自己想要实现的逻辑。我们时常会遇到在 Spring  启动的时候必须完成一些初始化的操作,如创建定时任务,创建连接池等。

如果没有 Spring 容器,不依赖于 Spring 的实现,回归 Java 类实现本身,我们可以在静态代码块,在类构造函数中实现相应的逻辑,Java  类的初始化顺序依次是静态变量 > 静态代码块 > 全局变量 > 初始化代码块 > 构造器。

比如,Log4j 的初始化,就是在 LogManager 的静态代码块中实现的:

static {     Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));     repositorySelector = new DefaultRepositorySelector(h);      String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,null);      if(override == null || "false".equalsIgnoreCase(override)) {           String configurationOptionStr = OptionConverter.getSystemProperty(DEFAULT_CONFIGURATION_KEY, null);           String configuratorClassName = OptionConverter.getSystemProperty(CONFIGURATOR_CLASS_KEY, null);            URL url = null;            if(configurationOptionStr == null) {             url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);             if(url == null) {               url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);             }           } else {             try {               url = new URL(configurationOptionStr);             } catch (MalformedURLException ex) {               url = Loader.getResource(configurationOptionStr);             }           }            if(url != null) {             LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");             try {                 OptionConverter.selectAndConfigure(url, configuratorClassName,LogManager.getLoggerRepository());             } catch (NoClassDefFoundError e) {                 LogLog.warn("Error during default initialization", e);             }           } else {               LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");           }     } else {             LogLog.debug("Default initialization of overridden by " +  DEFAULT_INIT_OVERRIDE_KEY + "property.");     } }

比如在构造函数中实现相应的逻辑:

@Component public class CustomBean {      @Autowired     private Environment env;      public CustomBean() {         env.getActiveProfiles();     } }

这里考验一下各位,上面的代码是否可以正常运行。—— 不行,构造函数中的env将会发生NullPointException异常。这是因为在 Spring  中将先初始化 Bean,也就是会先调用类的构造函数,然后才注入成员变量依赖的  Bean(@Autowired和@Resource注解修饰的成员变量),注意@Value等注解的配置的注入也是在构造函数之后。

PostConstruct

在 Spring 中,我们可以使用@PostConstruct在 Bean 初始化之后实现相应的初始化逻辑,@PostConstruct修饰的方法将在  Bean 初始化完成之后执行,此时 Bean 的依赖也已经注入完成,因此可以在方法中调用注入的依赖 Bean。

@Component public class CustomBean {      @Autowired     private Environment env;      @PostConstruce     public void init() {         env.getActiveProfiles();     } }

与@PostConstruct相对应的,如果想在 Bean 注销时完成一些清扫工作,如关闭线程池等,可以使用@PreDestroy注解:

@Component public class CustomBean {      @Autowired     private ExecutorService executor = Executors.newFixedThreadPool(1)      @PreDestroy     public void destroy() {         env.getActiveProfiles();     } }

InitializingBean

实现 Spring 的InitializingBean接口同样可以实现以上在 Bean  初始化完成之后执行相应逻辑的功能,实现InitializingBean接口,在afterPropertiesSet方法中实现逻辑:

@Component public class CustomBean implements InitializingBean {      private static final Logger LOG       = Logger.getLogger(InitializingBeanExampleBean.class);      @Autowired     private Environment environment;      @Override     public void afterPropertiesSet() throws Exception {         LOG.info(environment.getDefaultProfiles());     } }

ApplicationListener

我们可以在 Spring 容器初始化的时候实现我们想要的初始化逻辑。这时我们就可以使用到 Spring 的初始化事件。Spring  有一套完整的事件机制,在 Spring 启动的时候,Spring 容器本身预设了很多事件,在 Spring  初始化的整个过程中在相应的节点触发相应的事件,我们可以通过监听这些事件来实现我们的初始化逻辑。Spring 的事件实现如下:

与 Spring Context 生命周期相关的几个事件有以下几个:

因此,如果我们想在 Spring 启动的时候实现一些相应的逻辑,可以找到 Spring  启动过程中符合我们需要的事件,通过监听相应的事件来完成我们的逻辑:

@Component @Slf4j public class StartupApplicationListenerExample implements ApplicationListener<ContextRefreshedEvent> {      @Override     public void onApplicationEvent(ContextRefreshedEvent event) {         log.info("Subject ContextRefreshedEvent");     } }

除了通过实现ApplicationListener接口来监听相应的事件,Spring  的事件机制也实现了通过@EventListener注解来监听相对应事件:

@Component @Slf4j public class StartupApplicationListenerExample {      @EventListener     public void onApplicationEvent(ContextRefreshedEvent event) {         log.info("Subject ContextRefreshedEvent");     } }

Spring Event 是一套完善的进程内事件发布订阅机制,我们除了用来监听 Spring 内置的事件,也可以使用 Spring Event  实现自定义的事件发布订阅功能。

Constructor 注入

在学习 Spring 的注入机制的时候,我们都知道 Spring 可以通过构造函数、Setter  和反射成员变量注入等方式。上面我们在成员变量上通过@Autoware注解注入依赖 Bean,但是在 Bean 的构造函数函数中却无法使用到注入的 Bean(因为  Bean 还未注入),其实我们也是使用 Spring 的构造函数注入方式, 这也是 Spring 推荐的注入机制(在我们使用 IDEA  的时候,如果没有关闭相应的代码 Warning 机制,会发现在成员变量上的@Autoware是黄色的,也就是 idea 不建议的代码)。Spring  更推荐构造函数注入的方式:

@Component @Slf4j public class ConstructorBean {      private final Environment environment;      @Autowired     public LogicInConstructorExampleBean(Environment environment) {         this.environment = environment;         log.info(Arrays.asList(environment.getDefaultProfiles()));     } }

CommandLineRunner

如果我们的项目使用的是 Spring Boot,那么可以使用 Spring Boot 提供的 CommandLineRunner  接口来实现初始化逻辑,Spring Boot 将在启动初始化完成之后调用实现了CommandLineRunner的接口的run方法:

@Component @Slf4j public class CommandLineAppStartupRunner implements CommandLineRunner {      @Override     public void run(String...args) throws Exception {         log.info("Increment counter");     } }

并且,多个CommandLineRunner实现,可以通过@Order来控制它们的执行顺序。

SmartLifecycle

还有一种更高级的方法来实现我们的逻辑。这可以 Spring 高级开发必备技能哦。SmartLifecycle  不仅仅能在初始化后执行一个逻辑,还能再关闭前执行一个逻辑,并且也可以控制多个 SmartLifecycle  的执行顺序,就像这个类名表示的一样,这是一个智能的生命周期管理接口。

@Component public class SmartLifecycleExample implements SmartLifecycle {      private boolean isRunning = false;      @Override     public void start() {         System.out.println("start");         isRunning = true;     }      @Override     public int getPhase() {         // 默认为 0         return 0;     }      @Override     public boolean isAutoStartup() {         // 默认为 false         return true;     }      @Override     public boolean isRunning() {         // 默认返回 false         return isRunning;     }      @Override     public void stop(Runnable callback) {         System.out.println("stop(Runnable)");         callback.run();         isRunning = false;     }      @Override     public void stop() {         System.out.println("stop");          isRunning = false;     }  }

感谢各位的阅读,以上就是“如何掌握Spring”的内容了,经过本文的学习后,相信大家对如何掌握Spring这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯