亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBatch從入門到精通之StepScope作用域和用法詳解

 更新時(shí)間:2022年05月31日 10:29:47   作者:jackssybin  
這篇文章主要介紹了SpringBatch從入門到精通之StepScope作用域和用法詳解,主要包括IOC容器中幾種bean的作用范圍以及可能遇到的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

1.StepSope 是一種scope

在此之前,先說一下IOC容器中幾種bean的作用范圍:

  • singleton單例模式 – 全局有且僅有一個(gè)實(shí)例

  • prototype原型模式 – 每次獲取Bean的時(shí)候會(huì)有一個(gè)新的實(shí)例

  • request – request表示該針對(duì)每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean,同時(shí)該bean僅在當(dāng)前HTTP request內(nèi)有效

  • session – session作用域表示該針對(duì)每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean,同時(shí)該bean僅在當(dāng)前HTTP session內(nèi)有效

  • globalsession – global session作用域類似于標(biāo)準(zhǔn)的HTTP Session作用域,不過它僅僅在基于portlet的web應(yīng)用中才有意義

2.StepSope 是一種自定義step

目的是在每一次啟動(dòng)Job實(shí)例時(shí)底層單位(RPW或者也可是step)的參數(shù)可以靈活修改或者達(dá)到可變,因?yàn)橐粋€(gè)系統(tǒng)里可能有多個(gè)job實(shí)例,每個(gè)job實(shí)例對(duì)應(yīng)的參數(shù)是不一樣的。在step運(yùn)行期間需要獲取的job參數(shù)/stepContext/jobContext,因此需要自定義一個(gè)作用域,令其與Step的生命周期一致。

使用注解了。那么stepScope修飾的一定是一個(gè)@Bean

3.如何使用。@Value是支持spel表達(dá)式的

3.1 大部分場(chǎng)景是Spel 表達(dá)式。在底層reader/process/writer 中使用@Value獲取jobParamter/stepContext/jobContext

  • job參數(shù):#{jobParameters[xy]}

  • job運(yùn)行上下文:#{jobExecutionContext[xy]}

  • step運(yùn)行上下文:#{stepExecutionContext[xy]}

3.2 SpEL引用bean

  • bean對(duì)象:#{car}

  • bean對(duì)象屬性:#{car.brand}

  • bean對(duì)象方法:#{car.toString()}

  • 靜態(tài)方法屬性:#{T(java.lang.Math).PI}

3.3 系統(tǒng)屬性

  • 系統(tǒng)變量:systemProperties

  • 環(huán)境變量:#{systemEnvironment['HOME']}

3.4 運(yùn)算符號(hào)

  • if-else 運(yùn)算符(三目運(yùn)算符 ?:(temary), ?:(Elvis))

  • 比較運(yùn)算符(< , > , == , >= , <= , lt , gt , eg , le , ge)

  • 邏輯運(yùn)算符(and , or , not , |)

  • 正則表達(dá)式(#{admin.email matches ‘[a-zA-Z0-9._%±]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}’})

  • 算術(shù)運(yùn)算符(+,-,*,/,%,^(加號(hào)還可以用作字符串連接))

4.可能遇到問題

  • 問題: Scope 'step' is not active for the current thread;

Error creating bean with name 'scopedTarget.demo01StepScopeStep': Scope 'step' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for step scope

原因:看代碼

@Bean
    public Job demo01StepScopeJob(){
        return jobBuilderFactory.get("demo01StepScopeJob")
                .start(demo01StepScopeStepError(null))
                .build();
    }
    /** 
    ** 這個(gè)時(shí)候在 Step (demo01StepScopeStep) 中添加注解stepscope。
    ** Scope 'step' is not active for the current thread. 這個(gè)說的也很明白,step還沒有裝載初始化完成呢。
    ** 所以只有在step激活,即裝載成功之后才能獲取@Value 這種情況。我們可以把taskle 定義成個(gè)bean來獲取
    **/
    @Bean
    @StepScope 
    public Step demo01StepScopeStepError(@Value("${demo01.param.name}") String paramName){
        return stepBuilderFactory.get("demo01StepScopeStep")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        logger.info("=======demo01StepScopeStep======paramName:{}",paramName);
                        return null;
                    }
                }).build();
    }
    
    // 改造如下
    
    @Bean
    public Job demo01StepScopeJob(){
        return jobBuilderFactory.get("demo01StepScopeJob")
                .start(demo01StepScopeStep())
                .build();
    }

	//這個(gè)時(shí)候step上面的bean可以不要。因?yàn)閟tepScope只需要定義需要獲取@Value的
    public Step demo01StepScopeStep(){
        return stepBuilderFactory.get("demo01StepScopeStep")
                .tasklet(demo01StepScopeTasklet(null))
                .build();
    }

    @Bean
    @StepScope  //這里的@StepScope 可以有也可以不用。因?yàn)锧value只是在application.properties中的內(nèi)容
    public Tasklet demo01StepScopeTasklet(@Value("${demo01.param.name}") String paramName){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                logger.info("=======demo01StepScopeStep======paramName:{}",paramName);
                return null;
            }
        };
    }

這里面獲取的是配置文件的內(nèi)容。不是step內(nèi)的特定內(nèi)容。所以可以直接使用@Value在參數(shù)bean里。也可以直接在configuration內(nèi)。

若使用jobParam參數(shù)內(nèi)的@Value呢?那必須使@StepScope

	@Bean
    @StepScope
    public Tasklet demo01StepScopeTasklet(@Value("#{jobParameters[rnd]} ") String rnd){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                logger.info("=======demo01StepScopeTasklet======rnd:{}",rnd);
                return null;
            }
        };
    }

5.StepScope原理

org.springframework.batch.core.scope.StepScope.java

看出stepScope實(shí)現(xiàn)了BeanFactoryPostProcessor。引入了bpp即實(shí)例化之前做擴(kuò)展。這里是講stepScope給注冊(cè)到了spring容器中

獲取bean的時(shí)候AbstractBeanFactory#doGetBean。判斷bean不是mbd.isSingleton(),不是mbd.isPrototype(),若是自定義的即

mbd.getScope()。

那是如何獲取的呢StepScope#get(String, ObjectFactory) ->這里面會(huì)獲取StepContext內(nèi)容。

stepContext=getContext() ->這里面其實(shí)是直接從ThreadLocal中獲取內(nèi)容。獲取stepContext(這里面從有jobParam,stepContext)

那我們可以看到這個(gè)StepSynchronizationManager已經(jīng)有獲取的。那什么時(shí)候注冊(cè)進(jìn)去的呢?

AbstractStep#execute中在step的抽象類里面。執(zhí)行doExecute(stepExecution);之前的方法doExecutionRegistration

這里面將stepExecution添加進(jìn)ThreadLocal中。這里面可以認(rèn)為是threadlocal(其實(shí)里面是一個(gè)??梢源娑鄠€(gè)stepExecution!?。?,兼容step套step那種的。)

其實(shí)這里已經(jīng)能解答了。但還有個(gè)問題。@Value是如何從stepExecution中獲取jobParm/stepContext/jobContext的

額外(通過@value是如何在那個(gè)階段獲取值的呢):

springboot啟動(dòng)過程中,有兩個(gè)比較重要的過程,如下: 1 掃描,解析容器中的bean注冊(cè)到beanFactory上去,就像是信息登記一樣。 2 實(shí)例化、初始化這些掃描到的bean。

@Value的解析就是在第二個(gè)階段。BeanPostProcessor定義了bean初始化前后用戶可以對(duì)bean進(jìn)行操作的接口方法,它的一個(gè)重要實(shí)現(xiàn)類AutowiredAnnotationBeanPostProcessor正如javadoc所說的那樣,為bean中的@Autowired@Value注解的注入功能提供支持。下面是調(diào)用鏈

這里先簡(jiǎn)單介紹一下圖上的幾個(gè)類的作用。

AbstractAutowireCapableBeanFactory: 提供了bean創(chuàng)建,屬性填充,自動(dòng)裝配,初始胡。支持自動(dòng)裝配構(gòu)造函數(shù),屬性按名稱和類型裝配。實(shí)現(xiàn)了AutowireCapableBeanFactory接口定義的createBean方法。

AutowiredAnnotationBeanPostProcessor: 裝配bean中使用注解標(biāo)注的成員變量,setter方法, 任意的配置方法。比較典型的是@Autowired注解和@Value注解。

InjectionMetadata: 類的注入元數(shù)據(jù),可能是類的方法或?qū)傩缘?,在AutowiredAnnotationBeanPostProcessor類中被使用。

AutowiredFieldElement: 是AutowiredAnnotationBeanPostProcessor的一個(gè)私有內(nèi)部類,繼承InjectionMetadata.InjectedElement,描述注解的字段。

StringValueResolver: 一個(gè)定義了處置字符串值的接口,只有一個(gè)接口方法resolveStringValue,可以用來解決占位符字符串。本文中的主要實(shí)現(xiàn)類在PropertySourcesPlaceholderConfigurer#processProperties方法中通過lamda表達(dá)式定義的。供ConfigurableBeanFactory類使用。

PropertySourcesPropertyResolver: 屬性資源處理器,主要功能是獲取PropertySources屬性資源中的配置鍵值對(duì)。

PropertyPlaceholderHelper: 一個(gè)工具類,用來處理帶有占位符的字符串。形如${name}的字符串在該工具類的幫助下,可以被用戶提供的值所替代。替代途經(jīng)可能通過Properties實(shí)例或者PlaceholderResolver(內(nèi)部定義的接口)。

PropertyPlaceholderConfigurerResolver: 上一行所說的PlaceholderResolver接口的一個(gè)實(shí)現(xiàn)類,是PropertyPlaceholderConfigurer類的一個(gè)私有內(nèi)部類。實(shí)現(xiàn)方法resolvePlaceholder中調(diào)用了外部類的resolvePlaceholder方法。

6.自定義一個(gè)scope

定義JakcssybinScope

/**
 * 定義在同一個(gè)線程內(nèi),多次獲取同一個(gè)bean 獲取的是同一個(gè)。
 * 如果不用該注解 獲取的是不同的bean
 */
public class JackssybinScope implements Scope {

    private final ThreadLocal<Map<String, Object>> threadLoacal = new ThreadLocal<Map<String, Object>>() {
        @Override
        protected Map<String, Object> initialValue() {
            return new HashMap<String, Object>();
        }
    };

    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> scope = threadLoacal.get();
        Object obj = scope.get(name);

        // 不存在則放入ThreadLocal
        if (obj == null) {
            obj = objectFactory.getObject();
            scope.put(name, obj);

            System.out.println("Not exists " + name + "; hashCode: " + obj.hashCode());
        } else {
            System.out.println("Exists " + name + "; hashCode: " + obj.hashCode());
        }

        return obj;
    }

    public Object remove(String name) {
        Map<String, Object> scope = threadLoacal.get();
        return scope.remove(name);
    }

    public String getConversationId() {
        return null;
    }

    public void registerDestructionCallback(String arg0, Runnable arg1) {
    }

    public Object resolveContextualObject(String arg0) {
        return null;
    }

}

注入jackssybinScope

@Component
public class JackssybinBPP implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("==============注冊(cè)JackssybinBPP=========");
        beanFactory.registerScope("jackssybinScope", new JackssybinScope());
    }
}

引用

@Service
@Scope("jackssybinScope")
public class JackssybinHaveScopeService {
    public String getMessage() {
        return "Hello World!"+this.hashCode();
    }
}

未引用

@Service
public class JackssybinNoScopeService {
    public String getMessage() {
        return "Hello World!"+this.hashCode();
    }
}

測(cè)試

@SpringBootTest(classes = {Demo01StepScopeApplication.class})
public class JackssybinScopeTest {
    @Autowired
    ApplicationContext ctx;
    @Test
    public void jackssybinScopetest2(){
        JackssybinHaveScopeService service = ctx.getBean(JackssybinHaveScopeService.class);
        System.out.println(service.getMessage()+"="+service.hashCode());
        JackssybinHaveScopeService service2= ctx.getBean(JackssybinHaveScopeService.class);
        System.out.println(service2.getMessage()+"="+service2.hashCode());
        System.out.println("======================");
        JackssybinNoScopeService service3 = ctx.getBean(JackssybinNoScopeService.class);
        System.out.println(service3.getMessage()+"="+service3.hashCode());
        JackssybinNoScopeService service4= ctx.getBean(JackssybinNoScopeService.class);
        System.out.println(service4.getMessage()+"="+service4.hashCode());
    }
}

結(jié)果

Not exists jackssybinHaveScopeService; hashCode: 1842102517
Hello World!1842102517=1842102517
Exists jackssybinHaveScopeService; hashCode: 1842102517
Hello World!1842102517=1842102517
======================
Hello World!728236551=728236551
Hello World!728236551=728236551

結(jié)論:

  • jackssybinScope生效了。
  • ctx中的bean默認(rèn)是單例的。

代碼位置: github.com/jackssybin/…

到此這篇關(guān)于SpringBatch從入門到精通之StepScope作用域和用法詳解的文章就介紹到這了,更多相關(guān)SpringBatch StepScope作用域和用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloud使用Feign文件上傳、下載

    SpringCloud使用Feign文件上傳、下載

    這篇文章主要為大家詳細(xì)介紹了SpringCloud使用Feign文件上傳、下載功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • Mybatis重置Criteria的正確姿勢(shì)分享

    Mybatis重置Criteria的正確姿勢(shì)分享

    這篇文章主要介紹了Mybatis重置Criteria的正確姿勢(shì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Spring框架中ImportBeanDefinitionRegistrar的應(yīng)用詳解

    Spring框架中ImportBeanDefinitionRegistrar的應(yīng)用詳解

    這篇文章主要介紹了Spring框架中ImportBeanDefinitionRegistrar的應(yīng)用詳解,如果實(shí)現(xiàn)了ImportSelector接口,在配置類中被@Import加入到Spring容器中以后,Spring容器就會(huì)把ImportSelector接口方法返回的字符串?dāng)?shù)組中的類new出來對(duì)象然后放到工廠中去,需要的朋友可以參考下
    2024-01-01
  • Java上傳文件到服務(wù)器端的方法

    Java上傳文件到服務(wù)器端的方法

    這篇文章主要為大家詳細(xì)介紹了Java上傳文件到服務(wù)器端的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • SpringBoot通過Filter實(shí)現(xiàn)整個(gè)項(xiàng)目接口的SQL注入攔截詳解

    SpringBoot通過Filter實(shí)現(xiàn)整個(gè)項(xiàng)目接口的SQL注入攔截詳解

    這篇文章主要介紹了SpringBoot通過Filter實(shí)現(xiàn)整個(gè)項(xiàng)目接口的SQL注入攔截詳解,SQL注入是比較常見的網(wǎng)絡(luò)攻擊方式之一,在客戶端在向服務(wù)器發(fā)送請(qǐng)求的時(shí)候,sql命令通過表單提交或者url字符串拼接傳遞到后臺(tái)持久層,最終達(dá)到欺騙服務(wù)器執(zhí)行惡意的SQL命令,需要的朋友可以參考下
    2023-12-12
  • IntelliJ IDEA Java項(xiàng)目手動(dòng)添加依賴 jar 包的方法(圖解)

    IntelliJ IDEA Java項(xiàng)目手動(dòng)添加依賴 jar 包的方法(圖解)

    這篇文章主要介紹了IntelliJ IDEA Java項(xiàng)目手動(dòng)添加依賴 jar 包,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Spring Bean的屬性注入方式

    Spring Bean的屬性注入方式

    這篇文章主要介紹了Spring Bean的屬性注入方式的相關(guān)資料,需要的朋友可以參考下
    2018-02-02
  • Java中的共享鎖CountDownLatch及源碼解析

    Java中的共享鎖CountDownLatch及源碼解析

    這篇文章主要介紹了Java中的共享鎖CountDownLatch及源碼解析,CountDownLatch是一種同步輔助工具,允許一個(gè)或多個(gè)線程等待,直到在其它線程中執(zhí)行的一組操作完成;CountDownLatch使用指定的計(jì)數(shù)初始化,需要的朋友可以參考下
    2023-11-11
  • 淺談Java模板引擎性能對(duì)比

    淺談Java模板引擎性能對(duì)比

    本篇文章主要介紹了淺談Java模板引擎性能對(duì)比 ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Java struts2 package元素配置及實(shí)例解析

    Java struts2 package元素配置及實(shí)例解析

    這篇文章主要介紹了Java struts2 package元素配置及實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11

最新評(píng)論