zoukankan      html  css  js  c++  java
  • 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"/>

    搞定,这样就可以了,启动项目,定时器就会按时的执行。在以后如果在需要添加一个业务定时器,只需要定义类,并标注注解就行了,不需要额外的配置。维护起来只需关注定时器这个包下的类,方便维护。

    水平有限,只是做这么个改造实现,可能考虑的还不够多,例如:解析类中的代码效率啊,资源损耗啊。但主要还是说明下,注解在系统中的应用。还是很多场合可以用到。任何事物都是有两面性的,注解也是有利有弊。根据自己的项目,合理利用注解。

  • 相关阅读:
    TC(Total Commander)文件管理神器
    友盟 集成测试
    Channel SDK (渠道SDK) for Unity
    Prefab Assist插件
    Android资源(图片)命名规范
    FragmentTransaction的commit的异步操作
    面试2
    Git中.gitignore文件不起作用的解决以及Git中的忽略规则介绍
    Android必知必会-Android Studio修改包名
    Http标准协议Android网络框架——NoHttp
  • 原文地址:https://www.cnblogs.com/yanbincn/p/2554318.html
Copyright © 2011-2022 走看看