이 블로그에 글이 없으면 아주 좋은일이다...

 

왜냐면 대부분 쉽게 처리하고 삽질 안한거니까 ...

 

 

Spring boot에서 pom.xml에 외부 library 추가는 다음과 같이 한다.

 

<dependency>
	<groupId>DaouCrypto-20180824</groupId>
	<artifactId>DaouCrypto-20180824</artifactId>
	<version>1.0</version>
	<scope>system</scope>
	<systemPath>${basedir}/src/main/resources/external-lib/DaouCrypto-20180824.jar</systemPath>
</dependency>

 

scope가 system일때 systemPath property를 사용 가능한데

반드시 절대경로여야한다

classpath 안됨

외부 jar 추가하고 build까지는 잘 됐는데

runtime에서 NoClassDefFoundError를 뱉었다.

아래는 해결~

 

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <includeSystemScope>true</includeSystemScope>
  </configuration>
</plugin>

 

plugin에

  <configuration>
    <includeSystemScope>true</includeSystemScope>
  </configuration>

 

를 추가해주면 빌드도 잘 되고 java -jar ... 로 spring boot server를 올려도 아주 잘 작동된다.

 

 

 

출처 :https://stackoverflow.com/questions/30207842/add-external-library-jar-to-spring-boot-jar-internal-lib





꼬박 하루를 날렸다 ...


왜 autowired가 안되는지 이유를 몰라서 다른곳에서 너무 삽질했다




좀 더 자세하게 찾아봐야하지만



@Autowired will not work in a Quartz job implementation because it will not be instantiated by Spring ... 인걸 보면


Quartz 랑 Spring 사이에 무언가 있는 듯 하다 ...



같은 내용으로 검색하니 다른 개발자분들도 많은 블로그를 썼지만 java config는 별로 없기에...





Bean 등록할 때 다음과같이 setApplicationContextSchedulerContextKey("applicationContext"); 를 명시해준다


1
2
3
4
5
6
7
8
9
10
@Bean
public jaSchedulerFactoryBean schedulerFactoryBean() throws IOException, SchedulerException
{
    SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
    scheduler.setTriggers(jobOneTrigger(), jobTwoTrigger());
    scheduler.setQuartzProperties(quartzProperties());
    scheduler.setJobDetails(jobOneDetail(), jobTwoDetail());
    scheduler.setApplicationContextSchedulerContextKey("applicationContext");
    return scheduler;
}
cs







setApplicationContextSchedulerContextKey API 문서를 보면





public void setApplicationContextSchedulerContextKey(java.lang.String applicationContextSchedulerContextKey)


Set the key of an ApplicationContext reference to expose in the SchedulerContext, for example "applicationContext". Default is none. Only applicable when running in a Spring ApplicationContext.

Note: When using persistent Jobs whose JobDetail will be kept in the database, do not put an ApplicationContext reference into the JobDataMap but rather into the SchedulerContext.


In case of a QuartzJobBean, the reference will be applied to the Job instance as bean property. An "applicationContext" attribute will correspond to a "setApplicationContext" method in that scenario.


Note that BeanFactory callback interfaces like ApplicationContextAware are not automatically applied to Quartz Job instances, because Quartz itself is responsible for the lifecycle of its Jobs.


See Also:

JobDetailFactoryBean.setApplicationContextJobDataKey(java.lang.String), ApplicationContext



라고 되어있다




Job을 구현한 모든 클래스는 execute method를 구현하는데 메서드에서 넘어온 JobExecutionContext를 통해 Spring의 ApplicationContext를 찾는다



1
2
3
4
5
6
7
8
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
    ApplicationContext applicationContext = (ApplicationContext) context.getScheduler().getContext().get("applicationContext");
 
    BeanObject bean = applicationContext.getBean(BeanObject.class); 
 
    //bla bla...
}
cs





ㅠㅠㅠㅠㅠㅠㅠㅠㅠ 힘들었다





https://stackoverflow.com/questions/25719179/quartz-does-not-support-autowired

https://stackoverflow.com/questions/25719179/quartz-does-not-support-autowired

https://stackoverflow.com/questions/25719179/quartz-does-not-support-autowired



https://howtodoinjava.com/spring-batch/spring-beans-in-quartz-job/

https://howtodoinjava.com/spring-batch/spring-beans-in-quartz-job/

https://howtodoinjava.com/spring-batch/spring-beans-in-quartz-job/





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.*;
import org.quartz.impl.*;
 
public abstract class ChainableJob implements Job {
   private static final String CHAIN_JOB_CLASS = "chainedJobClass";
   private static final String CHAIN_JOB_NAME = "chainedJobName";
   private static final String CHAIN_JOB_GROUP = "chainedJobGroup";
   
   @Override
   public void execute(JobExecutionContext context) throws JobExecutionException {
      // execute actual job code
      doExecute(context);
 
      // if chainJob() was called, chain the target job, passing on the JobDataMap
      if (context.getJobDetail().getJobDataMap().get(CHAIN_JOB_CLASS) != null) {
         try {
            chain(context);
         } catch (SchedulerException e) {
            e.printStackTrace();
         }
      }
   }
   
   // actually schedule the chained job to run now
   private void chain(JobExecutionContext context) throws SchedulerException {
      JobDataMap map = context.getJobDetail().getJobDataMap();
      @SuppressWarnings("unchecked")
      Class jobClass = (Class) map.remove(CHAIN_JOB_CLASS);
      String jobName = (String) map.remove(CHAIN_JOB_NAME);
      String jobGroup = (String) map.remove(CHAIN_JOB_GROUP);
      
      
      JobDetail jobDetail = newJob(jobClass)
            .withIdentity(jobName, jobGroup)
            .usingJobData(map)
            .build();
         
      Trigger trigger = newTrigger()
            .withIdentity(jobName + "Trigger", jobGroup + "Trigger")
                  .startNow()      
                  .build();
      System.out.println("Chaining " + jobName);
      StdSchedulerFactory.getDefaultScheduler().scheduleJob(jobDetail, trigger);
   }
 
   protected abstract void doExecute(JobExecutionContext context) 
                                    throws JobExecutionException;
   
   // trigger job chain (invocation waits for job completion)
   protected void chainJob(JobExecutionContext context, 
                          Class jobClass, 
                          String jobName, 
                          String jobGroup) {
      JobDataMap map = context.getJobDetail().getJobDataMap();
      map.put(CHAIN_JOB_CLASS, jobClass);
      map.put(CHAIN_JOB_NAME, jobName);
      map.put(CHAIN_JOB_GROUP, jobGroup);
   }
}
cs






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.*;
import org.quartz.*;
 
public class TestJob extends ChainableJob {
 
   @Override
   protected void doExecute(JobExecutionContext context) 
                                   throws JobExecutionException {
      JobDataMap map = context.getJobDetail().getJobDataMap();
      System.out.println("Executing " + context.getJobDetail().getKey().getName() 
                         + " with " + new LinkedHashMap(map));
      
      boolean alreadyChained = map.get("jobValue"!= null;
      if (!alreadyChained) {
         map.put("jobTime"new Date().toString());
         map.put("jobValue"new Random().nextLong());
      }
      
      if (!alreadyChained && new Random().nextBoolean()) {
         chainJob(context, TestJob.class"secondJob""secondJobGroup");
      }
   }
   
}
cs





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import org.quartz.*;
import org.quartz.impl.*;
 
public class Test {
   
   public static void main(String[] args) throws Exception {
 
      // start up scheduler
      StdSchedulerFactory.getDefaultScheduler().start();
 
      JobDetail job = JobBuilder.newJob(TestJob.class)
             .withIdentity("firstJob""firstJobGroup").build();
 
      // Trigger our source job to triggers another
      Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("firstJobTrigger""firstJobbTriggerGroup")
            .startNow()
            .withSchedule(
                  SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
                  .repeatForever()).build();
 
      StdSchedulerFactory.getDefaultScheduler().scheduleJob(job, trigger);
      Thread.sleep(5000);   // let job run a few times
 
      StdSchedulerFactory.getDefaultScheduler().shutdown();
   }
   
}
cs







https://dzone.com/articles/job-chaining-quartz-and

https://dzone.com/articles/job-chaining-quartz-and

https://dzone.com/articles/job-chaining-quartz-and



아주 훌륭한 예제입니다 굿잡












저도 구글링으로도 해법을 못구하다가


어떤 글을 읽고 혹시해서 사용중인 프로그램 전부 종료하고


메모리확보 한 후

빌드쳤는데 잘 되네요!!!



만약 이걸로 고생하시는 분들에게 도움이 되었으면 좋겠어요 .. ㅎㅎㅎㅎㅎㅎㅎ











1
int drawableResourceId = this.getResources().getIdentifier("nameOfDrawable""drawable"this.getPackageName());
cs



I warn you, this way of obtaining identifiers is really slow, use only where needed.



https://stackoverflow.com/questions/3476430/how-to-get-a-resource-id-with-a-known-resource-name

https://stackoverflow.com/questions/3476430/how-to-get-a-resource-id-with-a-known-resource-name

https://stackoverflow.com/questions/3476430/how-to-get-a-resource-id-with-a-known-resource-name



https://yangyag.tistory.com/146

https://yangyag.tistory.com/146

https://yangyag.tistory.com/146











fragment는


현재 유저의 보고있는 화면단?을 알려주는


setUserVisibleHint라는 아주 좋은 메서드를 가지고 있지요 ..


근데 앱 실행시에 이게 onCreateView보다 먼저 호출 될 때가 있어서


사용자들에게 큰 혼란을 야기할 수 있습니다



그래서 아주 좋은 해결책 !





1
2
3
4
5
6
7
8
9
10
11
12
13
14
// create boolean for fetching data
private boolean isViewShown = false;
 
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (getView() != null) {
        isViewShown = true;
        // fetchdata() contains logic to show data when page is selected mostly asynctask to fill the data
        fetchData();
    } else {
        isViewShown = false;
    }
cs





https://stackoverflow.com/questions/24161160/setuservisiblehint-called-before-oncreateview-in-fragment

https://stackoverflow.com/questions/24161160/setuservisiblehint-called-before-oncreateview-in-fragment

https://stackoverflow.com/questions/24161160/setuservisiblehint-called-before-oncreateview-in-fragment







1
2
3
4
5
6
7
8
9
10
11
// you need to have a list of data that you want the spinner to display
List<String> spinnerArray =  new ArrayList<String>();
spinnerArray.add("item1");
spinnerArray.add("item2");
 
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
    this, android.R.layout.simple_spinner_item, spinnerArray);
 
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner sItems = (Spinner) findViewById(R.id.spinner1);
sItems.setAdapter(adapter);

cs



https://stackoverflow.com/questions/11920754/android-fill-spinner-from-java-code-programmatically

https://stackoverflow.com/questions/11920754/android-fill-spinner-from-java-code-programmatically

https://stackoverflow.com/questions/11920754/android-fill-spinner-from-java-code-programmatically


+ Recent posts