最近公司使用Jfinal開發項目,不知道什麼緣由Jfinal和其餘的幾個插件集成的時候,事物管理並不那麼隨心,因此就選擇了Spring做爲Jfinal的插件來管理事物.廢話很少說,直接上代碼.java
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.javagit
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.javaweb
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.javaspring
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.xmlexpress
<?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-springmybatis
測試環境還集成了activiti mybatisapp