java注解應用


在現在項目中注解應用越來越廣泛。為了有更深的理解,前面學習了java注解使用的一些原理,做了相關的總結和梳理,對注解有了更深的認識。趁熱打鐵,利用理解到的注解做點東西吧。結合日常工作中的一個點,利用注解做一些改造,也可以知道注解在實際項目中的用處。方便以后碰到相關情況可以利用。

廢話不多說,直入正題:

一般的管理系統中,都會有定時執行的任務,一般用於按一定規律進行統計。比如日,周,月的統計,業務邏輯不需要和人為結合的。這種情況就不需要在系統中做一個模塊功能讓用戶自己點擊觸發了。可以利用框架中的定時觸發器來做。設定時間,到點觸發執行。我們項目組中俗稱:“日終”,但並不准確。還是定時器比較好。

定時器實現現在比較流行的是:spring + quartz 的框架。應用起來也比較簡單:

1、定義需要定時觸發的業務類;

之后就是xml中的配置。

2、包裝業務類為定時器認識的類;

3、為需要定時出發的類,聲明一個定時器,並聲明出發時間;

4、將定時器注入到定時器的factory;

如下:

a、業務類:

/**
 * 業務類
 * 
 * @author yanbin
 * 
 */
public class Job1 {

    public void execute() {
        System.out.println("job1 say");
    }

}

b、spring trigger.xml的配置

<!--1、 注入配置日終 -->
<bean id="job1" class="trigger.Job1" />

<!--2、包裝業務類為定時器類 -->
<bean id="task" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <!-- 調用的類--> 
    <property name="targetObject"> 
        <ref bean="job1"/> 
    </property>  
    <!-- 調用類中的方法 --> 
    <property name="targetMethod"> 
        <value>execute</value> 
    </property> 
</bean>

<!-- 3、定義觸發時間 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail">
        <ref bean="task"/>
    </property> 
    <!-- cron定時表達式 -->
    <property name="cronExpression">
        <value>0/3 * * * * ?</value>
    </property>
</bean>

<!-- 4、注入factory設置調度 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
            <list>
                <ref bean="cronTrigger" />
            </list>
        </property>
</bean>

這樣就完成了一個定時器的實現,定時器會在spring容器啟動的時候同時啟動。在應用正常運行的情況下,到指定的時間調用業務類執行。

但是看了這樣的一個實現方式,如果再需要配置一個定時器,job2,配置業務bean,MethodInvokingJobDetailFactoryBean,CronTriggerBean,添加到SchedulerFactoryBean。同樣類似的配置。漸漸的在系統中業務復雜了,定時器需求越來越多,配置越來越多。這個trigger.xml將越來越龐大,可能會導致不好維護。

這個時候,注解就派上用場了。自己嘗試了利用注解對這個實現進行改造。利用的其實還是注解的基本原理來實現(mark前文)。主要思路:

1、定義注解

2、標記業務類,執行業務方法。(使用注解)

3、從spring容器中,獲取標記的業務類,業務方法。

4、繼承spring的trigger解析,重寫實現方法。注入到SchedulerFactoryBean中。(解析注解)

上碼:

a、定義兩個注解:

/**
 * 定時器標記類注解
 * 
 * @author yanbin
 * 
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface TriggerType {

    String value() default "";

    /** 定義定時器觸發時間 */
    String cronExpression() default "";

}
/**
 * 定時器執行方法標記注解
 * 
 * @author yanbin
 * 
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TriggerMethod {

    String value() default "";

}

 

b、業務類使用注解:

/**
 * 業務類
 * 
 * @author yanbin
 * 
 */
@TriggerType(cronExpression = "0/3 * * * * ?") //指定定時時間
public class Job1 {

    @TriggerMethod
    public void execute() {
        System.out.println("job1 say");
    }

}

c、繼承重寫spring實現,加入解析注解

/**
 * 解析日終類
 * 
 * @author yanbin
 * 
 */
public class MySchedulerFactoryBean extends SchedulerFactoryBean {

    /** 日志 */
    protected Log log = LogFactory.getLog(MySchedulerFactoryBean.class.getName());

    /** Spring 上下文 */
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public void registerJobsAndTriggers() throws SchedulerException {
        try {
            // 獲取所有bean name
            String[] beanNames = applicationContext.getBeanNamesForType(Object.class);
            for (String beanName : beanNames) {
                Class<?> targetClass = applicationContext.getType(beanName);
                // 循環判斷是否標記了TriggerType注解
                if (targetClass.isAnnotationPresent(TriggerType.class)) {
                    Object targetObject = applicationContext.getBean(beanName);
                    TriggerType triggerType = (TriggerType) targetClass.getAnnotation(TriggerType.class);
                    // 獲取時間表達式
                    String cronExpression = triggerType.cronExpression();
                    String targetMethod = "";
                    // 確定標記了TriggerMethod注解的方法名
                    Method[] methods = targetClass.getDeclaredMethods();
                    for (Method method : methods) {
                        if (method.isAnnotationPresent(TriggerMethod.class)) {
                            targetMethod = method.getName();
                        }
                    }
                    // 注冊定時器業務類
                    registerJobs(targetObject, targetMethod, beanName, cronExpression);
                }
            }
        } catch (Exception e) {
            log.error(e);
        }
    }

    /**
     * 注冊定時器
     * 
     * @param targetObject
     * @param targetMethod
     * @param beanName
     * @param cronExpression
     * @throws Exception
     */
    private void registerJobs(Object targetObject, String targetMethod, String beanName, String cronExpression)
            throws Exception {
        // 聲明包裝業務類
        MethodInvokingJobDetailFactoryBean jobDetailFactoryBean = new MethodInvokingJobDetailFactoryBean();
        jobDetailFactoryBean.setTargetObject(targetObject);
        jobDetailFactoryBean.setTargetMethod(targetMethod);
        jobDetailFactoryBean.setBeanName(beanName);
        jobDetailFactoryBean.afterPropertiesSet();

        // 獲取JobDetail
        JobDetail jobDetail = jobDetailFactoryBean.getObject();

        // 聲明定時器
        CronTriggerBean cronTriggerBean = new CronTriggerBean();
        cronTriggerBean.setJobDetail(jobDetail);
        cronTriggerBean.setCronExpression(cronExpression);
        cronTriggerBean.setBeanName(beanName + "CronBean");
        cronTriggerBean.afterPropertiesSet();

        // 將定時器注冊到factroy
        List<Trigger> triggerList = new ArrayList<Trigger>();
        triggerList.add(cronTriggerBean);
        Trigger[] triggers = (Trigger[]) triggerList.toArray(new Trigger[triggerList.size()]);
        setTriggers(triggers);
        super.registerJobsAndTriggers();
    }

}

d、在spring的容器xml配置文件中,將這個解析類的bean放入容器中,開始就初始化。

<!-- 自定義設置計時器調度 -->
<bean id="scheduler" class="trigger.MySchedulerFactoryBean"/>

搞定,這樣就可以了,啟動項目,定時器就會按時的執行。在以后如果在需要添加一個業務定時器,只需要定義類,並標注注解就行了,不需要額外的配置。維護起來只需關注定時器這個包下的類,方便維護。

水平有限,只是做這么個改造實現,可能考慮的還不夠多,例如:解析類中的代碼效率啊,資源損耗啊。但主要還是說明下,注解在系統中的應用。還是很多場合可以用到。任何事物都是有兩面性的,注解也是有利有弊。根據自己的項目,合理利用注解。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM