Jfinal集成Spring插件

Stella981
• 阅读 578

最近公司使用Jfinal开发项目,不知道什么原因Jfinal和其他的几个插件集成的时候,事物管理并不那么随心,所以就选择了Spring作为Jfinal的插件来管理事物.废话不多说,直接上代码.

public class MyConfig extends JFinalConfig{

    @Override
    public void configConstant(Constants me) {
        IocKit.processJFinalConfig(this);
        loadPropertyFile("db.properties");
        me.setEncoding("UTF-8");
        me.setDevMode(getPropertyToBoolean("devMode", true));
    }

    @Override
    public void configRoute(Routes me) {
        System.out.println("configRoute");
        me.add("/blog", BlogController.class);
    }

    @Override
    public void configPlugin(Plugins me) {
        SpringPlugin springPlugin = new SpringPlugin("classpath*:spring/applicationContext-*.xml");
        me.add(springPlugin);
        SpringDataSourceProvider prov = new SpringDataSourceProvider(springPlugin);
        // 配置ActiveRecord插件,将jfinal的事物交给Spring管理
        ActiveRecordPlugin arp = new ActiveRecordPlugin(prov);
        me.add(arp);
        arp.addMapping("system_admin", SystemAdmin.class);
        
    }

    @Override
    public void configInterceptor(Interceptors me) {
        System.out.println("configInterceptor");
    }

    @Override
    public void configHandler(Handlers me) {
        System.out.println("configHandler");
    }

    @Override
    public void configEngine(Engine me) {
        System.out.println("configEngine");
    }

}

IocKit.java

public class IocKit {

    // ioc @Inject @Value @Autowired
    static AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor;
    // ioc @Resource
    static CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor;

    public static AutowiredAnnotationBeanPostProcessor getAutowiredAnnotationBeanPostProcessor() {
        Assert.notNull(autowiredAnnotationBeanPostProcessor,
                "The main autowiredAnnotationBeanPostProcessor is null, initialize SpringPlugin first");
        return autowiredAnnotationBeanPostProcessor;
    }

    public static CommonAnnotationBeanPostProcessor getCommonAnnotationBeanPostProcessor() {
        Assert.notNull(commonAnnotationBeanPostProcessor,
                "The main commonAnnotationBeanPostProcessor is null, initialize SpringPlugin first");
        return commonAnnotationBeanPostProcessor;
    }

    // --------------------------------------------------
    // JFinalConfig
    // --------------------------------------------------

    /**
     * @Title: 处理 JFinalConfig
     */
    public static void processJFinalConfig(JFinalConfig finalConfig) {
        ApplicationContext ctx = org.springframework.web.context.support.WebApplicationContextUtils
                .getWebApplicationContext(JFinal.me().getServletContext());
        processJFinalConfig(finalConfig, ctx);
    }

    /**
     * @Title: 处理 JFinalConfig
     */
    public static void processJFinalConfig(JFinalConfig jfinalConfig, ApplicationContext ctx) {
        Assert.notNull(ctx, "ApplicationContext not be null");
        Assert.notNull(jfinalConfig, "jfinalConfig not be null");
        AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = setBeanFactory(
                new AutowiredAnnotationBeanPostProcessor(), ctx);
        CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor = setBeanFactory(
                new CommonAnnotationBeanPostProcessor(), ctx);

        processInjection(jfinalConfig, commonAnnotationBeanPostProcessor, autowiredAnnotationBeanPostProcessor);
    }

    /**
     * @Title: 注入 bean 调用
     */
    public static void invokeForProcessInjection(Object invocation) {
        Invocation inv = as(invocation, Invocation.class);
        Controller controller = inv.getController();
        processInjection(controller);
        inv.invoke();
    }

    public static void processInjection(Object bean) {
        processInjection(bean, commonAnnotationBeanPostProcessor, autowiredAnnotationBeanPostProcessor);
    }

    // ---------------------------------------------------------
    // function
    // ---------------------------------------------------------

    static void init(ApplicationContext ctx) {
        autowiredAnnotationBeanPostProcessor = setBeanFactory(new AutowiredAnnotationBeanPostProcessor(), ctx);
        commonAnnotationBeanPostProcessor = setBeanFactory(new CommonAnnotationBeanPostProcessor(), ctx);
    }

    static <T extends BeanFactoryAware> T setBeanFactory(T beanPostProcessor, ApplicationContext ctx) {
        beanPostProcessor.setBeanFactory(ctx.getAutowireCapableBeanFactory());
        return beanPostProcessor;
    }

    static void processInjection(Object bean, CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor,
            AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor) {
        commonAnnotationBeanPostProcessor.postProcessPropertyValues(null, null, bean, null);
        autowiredAnnotationBeanPostProcessor.processInjection(bean);
    }
    
    // ----------------------------------------------------------------
    // as proxy
    // ----------------------------------------------------------------

    private final static Map<String, Method> methodCache = new HashMap<String, Method>(16);

    private static Method cachedMethod(Class<?> type, Method method) throws NoSuchMethodException {
        String name = method.getName();
        String key = type.getName() + "." + name;

        Method m = methodCache.get(key);

        if (m == null) {
            synchronized (methodCache) {
                m = methodCache.get(key);
                if (m == null) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    try {
                        // Actual method name matches always come first
                        m = type.getMethod(name, parameterTypes);
                    } catch (SecurityException ignore) {
                        m = type.getDeclaredMethod(name, parameterTypes);
                    }

                    methodCache.put(key, m);
                }
            }
        }
        return m;
    }

    /**
     * Create a proxy for the wrapped object allowing to typesafely invoke
     * methods on it using a custom interface
     *
     * @param proxyType
     *            The interface type that is implemented by the proxy
     * @return A proxy for the wrapped object
     */
    @SuppressWarnings("unchecked")
    private static <P> P as(final Object object, Class<P> proxyType) {
        final Class<?> clazz = object.getClass();

        final InvocationHandler handler = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Method m = cachedMethod(clazz, method);
                boolean accessible = m.isAccessible();
                try {
                    if (!accessible) m.setAccessible(true);
                    return m.invoke(object, args);
                } finally {
                    m.setAccessible(accessible);
                }
            }
        };

        return (P) Proxy.newProxyInstance(proxyType.getClassLoader(), new Class[] { proxyType }, handler);
    }

    private static interface Invocation {
        void invoke();

        Controller getController();
    }
}

SpringDataSourceProvider.java

public class SpringDataSourceProvider implements IDataSourceProvider {
    
    private static final String proxyDsName = "proxyDataSource";

    private SpringPlugin springPlugin;
    
    private String beanName;

    public SpringDataSourceProvider(SpringPlugin springPlugin, String beanName) {
        this.springPlugin = springPlugin;
        this.beanName = beanName;
    }
    public SpringDataSourceProvider(SpringPlugin springPlugin) {
        this.springPlugin = springPlugin;
        this.beanName = proxyDsName;
    }

    public DataSource getDataSource() {
        ApplicationContext ctx = springPlugin.getApplicationContext();
        return (DataSource)ctx.getBean(beanName,TransactionAwareDataSourceProxy.class);
    }
}

SpringPlugin.java

private static boolean isStarted = false;
    private String[] configurations;
    private ApplicationContext ctx;
    
    public SpringPlugin() {}

    public SpringPlugin(ApplicationContext ctx) {
        this.setApplicationContext(ctx);
    }
    
    public SpringPlugin(String... configurations) {
        this.configurations = configurations;
    }

    public void setApplicationContext(ApplicationContext ctx) {
        Assert.notNull(ctx, "ApplicationContext can not be null.");
        this.ctx = ctx;
    }
    
    public ApplicationContext getApplicationContext() {
        return this.ctx ;
    }

    public boolean start() {
        if (isStarted) {
            return true;
        }else if (!isStarted && configurations != null){
            ctx = new FileSystemXmlApplicationContext(configurations);
        }else {
            ctx = new FileSystemXmlApplicationContext(PathKit.getWebRootPath() + "/WEB-INF/applicationContext.xml");
        }
        Assert.notNull(ctx, "ApplicationContext can not be null.");
        IocKit.init(ctx);
        return isStarted = true;
    }

    public boolean stop() {
        ctx = null;
        isStarted = false;
        return true;
    }
}

applicationContext-core.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context" 
        default-autowire="byName"
        xmlns:aop="http://www.springframework.org/schema/aop" 
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:tx="http://www.springframework.org/schema/tx" 
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
                            http://www.springframework.org/schema/beans 
                            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                            http://www.springframework.org/schema/util 
                            http://www.springframework.org/schema/util/spring-util-3.2.xsd
                            http://www.springframework.org/schema/tx 
                            http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
                            http://www.springframework.org/schema/context 
                            http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    <!-- 引入配置文件 -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:db.properties"/>
    </bean>
    <!-- dataSource配置 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="filters" value="log4j"/>
        <property name="maxActive" value="5"/>
        <property name="initialSize" value="1"/>
        <property name="maxWait" value="6000"/>
    </bean>
    
    <bean id="proxyDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
        <constructor-arg>
            <ref bean="dataSource" />
        </constructor-arg>
    </bean>
    
    <!-- 声明式事务的配置 -->
    <!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 配置事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="delete*" propagation="REQUIRED" read-only="false" />
            <tx:method name="insert*" propagation="REQUIRED" read-only="false" />
            <tx:method name="update*" propagation="REQUIRED" read-only="false" />
            <tx:method name="find*" propagation="SUPPORTS" />
            <tx:method name="get*" propagation="SUPPORTS" />
            <tx:method name="select*" propagation="SUPPORTS" />
        </tx:attributes>
    </tx:advice>
    <!-- 把事务控制在Service层 -->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(public * cn.minions.testSpring.Service.impl.*.*(..))" />
        <aop:advisor pointcut-ref="pointcut" advice-ref="txAdvice" />
    </aop:config>
    <context:component-scan base-package="cn.minions.testSpring" />
</beans>

完整测试项目的地址:https://gitee.com/fhcspring/jfinal-spring

测试环境还集成了activiti mybatis

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
JBolt插件
JFinal开发Eclipse极速编辑器体验升级,前端代码写的飞起。这两天就会升级,等波总发布新版JFinal。JBolt插件官网:http://jbolt.cn(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fjbolt.cn%2F)视频演示地址:http
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
JFinal 整合Quartz
    项目中要加入调度和计划任务等功能,所以选择Quartz调度插件,原先都是在S2SH上整合的。现在项目用JFinal框架,不得不说JFinal框架的定制性真好,可以自己根据项目要求进行修改,并且很节省时间。    原先当然是先找有没有JFinal的quartz插件,先是找到了JFinalext,里面有一个QuartzPlugin
Stella981 Stella981
3年前
JFinal的junit单元测试支持
在jfinal开发中不能直接使用junit单元测试,所以写了以下工具。原理是在运行junit测试方法之前启动jfinal的插件,运行完成后关闭插件。importorg.junit.After;importorg.junit.Before;importcom.jfinal.config.Constants;
Wesley13 Wesley13
3年前
JBolt
 JBolt是一个JFinal极速开发框架定制版IDE插件目前仅有Eclipse插件版,Idea插件版正在开发中。更新日志:http://www.jfinal.com/share/977(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.jfinal.com%
Stella981 Stella981
3年前
Eclipse插件开发_学习_00_资源帖
一、官方资料 1.eclipseapi(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fhelp.eclipse.org%2Fmars%2Findex.jsp%3Ftopic%3D%252Forg.eclipse.platform.doc.isv%252Fguide%2
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究