首页 > 代码库 > 模拟程序的入口与事务管理

模拟程序的入口与事务管理

模拟程序的入口与事务管理

 


虚拟机访问java程序的入口的格式是:    public static void main(String... args){}

我们可以自定义自己的程序入口,比如: public static void main(){}
无参main方法作为程序的入口

被spring的 @Service注解的类是怎样管理事务
是被注解的类的方法都在前后,开启事务和关闭事务
还是同一个被 @Service注解的类共享一个事务
如果是一个service调用另一个service时的事务开启几个

just Follow me and Solve question above


一、程序的入口
我们定义了三个方法来鉴别被主函数识别的程序的入口是否准确
/Annotation_Transaction/src/yuki/annotation/transaction/controller/Main.java - version=NOT_END

package yuki.annotation.transaction.controller;import yuki.annotation.transaction.global.AppContext;import yuki.annotation.transaction.service.ProcessService;import yuki.annotation.transaction.service.ProcessServiceImp;/** * 自定义的主函数 * * @author yuki */public class Main {    public static void main() {        System.out.println("无参主方法执行中:main...");    }}

/Annotation_Transaction/src/yuki/annotation/transaction/controller/Main2.java - version=FINAL

package yuki.annotation.transaction.controller;public class Main2 {    public void main() {            }}

/Annotation_Transaction/src/yuki/annotation/transaction/controller/Main3.java - version=FINAL

package yuki.annotation.transaction.controller;public class Main3 {    public void main(String[] args) {    }}

 


上述的哪些方法可以成为程序的入口,这个需要我们自己定义

程序还是需要通过主函数才能被虚拟机进入
而定义的主函数需要扫描出来,所以需要一个工具类
这个类的代码在网上可以搜索到
http://www.cnblogs.com/phoebus0501/archive/2011/03/13/1982841.html
这段代码中使用的是斜杠/和点.的字符替换来切换文件名与包名

/Annotation_Transaction/src/yuki/annotation/transaction/util/ClassUtil.java- version=FINAL

package yuki.annotation.transaction.util;import java.io.File;import java.io.FileFilter;import java.io.IOException;import java.net.JarURLConnection;import java.net.URL;import java.net.URLDecoder;import java.util.Enumeration;import java.util.LinkedHashSet;import java.util.Set;import java.util.jar.JarEntry;import java.util.jar.JarFile;/** * 通过包名获得它下面所有的类 *  * @参考 * http://www.cnblogs.com/phoebus0501/archive/2011/03/13/1982841.html *  * @author yuki */public class ClassUtil {    /**     * 从包package中获取所有的Class     * @param pack 包名     * @return     */    public static Set<Class<?>> getClasses(String pack) {        // 第一个class类的集合        Set<Class<?>> classes = new LinkedHashSet<Class<?>>();        // 是否循环迭代        boolean recursive = true;        // 获取包的名字 并进行替换        String packageName = pack;        String packageDirName = packageName.replace(‘.‘, ‘/‘);        // 定义一个枚举的集合 并进行循环来处理这个目录下的things        Enumeration<URL> dirs;        try {            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);            // 循环迭代下去            while (dirs.hasMoreElements()) {                // 获取下一个元素                URL url = dirs.nextElement();                // 得到协议的名称                String protocol = url.getProtocol();                // 如果是以文件的形式保存在服务器上                if ("file".equals(protocol)) {//                    System.err.println("file类型的扫描");                    // 获取包的物理路径                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");                    // 以文件的方式扫描整个包下的文件 并添加到集合中                    findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);                } else if ("jar".equals(protocol)) {                    // 如果是jar包文件                    // 定义一个JarFile//                    System.err.println("jar类型的扫描");                    JarFile jar;                    try {                        // 获取jar                        jar = ((JarURLConnection) url.openConnection()).getJarFile();                        // 从此jar包 得到一个枚举类                        Enumeration<JarEntry> entries = jar.entries();                        // 同样的进行循环迭代                        while (entries.hasMoreElements()) {                            // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件                            JarEntry entry = entries.nextElement();                            String name = entry.getName();                            // 如果是以/开头的                            if (name.charAt(0) == ‘/‘) {                                // 获取后面的字符串                                name = name.substring(1);                            }                            // 如果前半部分和定义的包名相同                            if (name.startsWith(packageDirName)) {                                int idx = name.lastIndexOf(‘/‘);                                // 如果以"/"结尾 是一个包                                if (idx != -1) {                                    // 获取包名 把"/"替换成"."                                    packageName = name.substring(0, idx).replace(‘/‘, ‘.‘);                                }                                // 如果可以迭代下去 并且是一个包                                if ((idx != -1) || recursive) {                                    // 如果是一个.class文件 而且不是目录                                    if (name.endsWith(".class") && !entry.isDirectory()) {                                        // 去掉后面的".class" 获取真正的类名                                        String className = name.substring(packageName.length() + 1, name.length() - 6);                                        try {                                            // 添加到classes                                            classes.add(Class.forName(packageName + ‘.‘ + className));                                        } catch (ClassNotFoundException e) {                                            // log.error("添加用户自定义视图类错误 找不到此类的.class文件");                                            e.printStackTrace();                                        }                                    }                                }                            }                        }                    } catch (IOException e) {                        // log.error("在扫描用户定义视图时从jar包获取文件出错");                        e.printStackTrace();                    }                }            }        } catch (IOException e) {            e.printStackTrace();        }        return classes;    }    /**     * 以文件的形式来获取包下的所有Class     * @param packageName     * @param packagePath     * @param recursive     * @param classes     */    protected static void findAndAddClassesInPackageByFile(String packageName,                        String packagePath, final boolean recursive, Set<Class<?>> classes) {        // 获取此包的目录 建立一个File        File dir = new File(packagePath);        // 如果不存在或者 也不是目录就直接返回        if (!dir.exists() || !dir.isDirectory()) {            // log.warn("用户定义包名 " + packageName + " 下没有任何文件");            return;        }        // 如果存在 就获取包下的所有文件 包括目录        File[] dirfiles = dir.listFiles(new FileFilter() {            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)            public boolean accept(File file) {                return (recursive && file.isDirectory())|| (file.getName().endsWith(".class"));            }        });        // 循环所有文件        for (File file : dirfiles) {            // 如果是目录 则继续扫描            if (file.isDirectory()) {                findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);            } else {                // 如果是java类文件 去掉后面的.class 只留下类名                String className = file.getName().substring(0, file.getName().length() - 6);                try {                    // 添加到集合中去                    // classes.add(Class.forName(packageName + ‘.‘ +                    // className));                    // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + ‘.‘ + className));                } catch (ClassNotFoundException e) {                    // log.error("添加用户自定义视图类错误 找不到此类的.class文件");                    e.printStackTrace();                }            }        }    }}

 

写主函数,主函数是程序的入口
/**

 * 进入反射,就好像进入了二次元

 * 一次元的世界好无聊,大家来二次元的世界玩一玩吧

 */
/Annotation_Transaction/src/yuki/annotation/transaction/Demo.java - version=NOT_END

package yuki.annotation.transaction;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.Iterator;import java.util.Set;import yuki.annotation.transaction.global.AppContext;import yuki.annotation.transaction.global.MainAdvice;import yuki.annotation.transaction.global.Service;import yuki.annotation.transaction.util.ClassUtil;/** * 程序的入口 *  * 进入反射,就好像进入了二次元 * 一次元的世界好无聊,大家来二次元的世界玩一玩吧 * @author yuki * */public class Demo {    /**     * 主函数     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {                //扫描根目录下所有的Class        Set<Class<?>> clazzes = ClassUtil.getClasses("yuki");        /*for(Class<?> clazz : clazzes){            System.out.println(clazz.getName());        }*/                //找到入参为空的main方法        Method method = null;        Class<?> clazz = null;        //找到第一个含有无入参main方法的        Iterator<Class<?>> clazzIter = clazzes.iterator();        while(clazzIter.hasNext()){            //获取当前遍历到的类            clazz = clazzIter.next();            /*Method[] ms = clazz.getMethods();            for(Method m : ms){                if(!Arrays.asList(Object.class.getMethods()).contains(m))                    System.out.println(clazz.getName() + ", " + m.getName());            }*/                        //如果遇到了公开静态无参的main方法就记录并跳出            try {                method = clazz.getMethod("main", new Class<?>[]{});//                System.out.println(clazz.getName() + ", " + method);                //判断方法是否为公开静态方法                int mod = method.getModifiers();//                System.out.println(Modifier.isPublic(mod) + ", " + Modifier.isStatic(mod));                if(Modifier.isPublic(mod) && Modifier.isStatic(mod))                    break;            } catch (Exception e) {                //do nothing...            }        }//执行获取到的方法并执行加工后的方法        System.out.println(clazz.getName() + ", " + method.getName());        MainAdvice main = new MainAdvice(clazz.newInstance(), method);        main.invoke();    }}

扫描所有的类并遍历扫描出的类的方法
如果方法是无参公开静态方法,就判定位程序的入口,停止遍历,执行主函数
主函数的前后也可以在另一个类中定义执行前与执行后的日志输出
/Annotation_Transaction/src/yuki/annotation/transaction/global/MainAdvice.java - version=FINAL

 

package yuki.annotation.transaction.global;import java.lang.reflect.Method;/** * 在无参主方法前后要加入的通知 * * @author yuki */public class MainAdvice {        private Object ret;    public MainAdvice(Object target, Method method) throws Exception {        System.out.println("无参main方法执行前...");        ret = method.invoke(target, new Object[]{});        System.out.println("无参main方法执行后...");    }        public Object invoke() throws Exception {        return ret;    } }

 

 

 

运行结果如下:

yuki.annotation.transaction.controller.Main, main无参main方法执行前...无参主方法执行中:main...无参main方法执行后...

 


二、定义注解和读取注解
注解其实就是一个标签,被虚拟机和在虚拟机之上的程序读取
/Annotation_Transaction/src/yuki/annotation/transaction/global/Service.java - version=FINAL
这里 @Retention(RetentionPolicy.RUNTIME),表示在运行时注解可以被读
如果不标注默认是RetentionPolicy.CLASS它的意思是直接的内容只被储存在类中,但是不能读取出来

package yuki.annotation.transaction.global;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 被它注解的类会被程序动态的添加事务 * * @author yuki */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Service {}

/Annotation_Transaction/src/yuki/annotation/transaction/Demo.java - version=FINAL

把所有的含有 @Service注解的类放在一张映射实体中

package yuki.annotation.transaction;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.Iterator;import java.util.Set;import yuki.annotation.transaction.global.AppContext;import yuki.annotation.transaction.global.MainAdvice;import yuki.annotation.transaction.global.Service;import yuki.annotation.transaction.util.ClassUtil;/** * 程序的入口 *  * 进入反射,就好像进入了二次元 * 一次元的世界好无聊,大家来二次元的世界玩一玩吧 * @author yuki * */public class Demo {    /**     * 主函数     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {                //扫描根目录下所有的Class        Set<Class<?>> clazzes = ClassUtil.getClasses("yuki");        /*for(Class<?> clazz : clazzes){            System.out.println(clazz.getName());        }*/                //找到入参为空的main方法        Method method = null;        Class<?> clazz = null;        //找到第一个含有无入参main方法的        Iterator<Class<?>> clazzIter = clazzes.iterator();        while(clazzIter.hasNext()){            //获取当前遍历到的类            clazz = clazzIter.next();            /*Method[] ms = clazz.getMethods();            for(Method m : ms){                if(!Arrays.asList(Object.class.getMethods()).contains(m))                    System.out.println(clazz.getName() + ", " + m.getName());            }*/                        //如果遇到了公开静态无参的main方法就记录并跳出            try {                method = clazz.getMethod("main", new Class<?>[]{});//                System.out.println(clazz.getName() + ", " + method);                //判断方法是否为公开静态方法                int mod = method.getModifiers();//                System.out.println(Modifier.isPublic(mod) + ", " + Modifier.isStatic(mod));                if(Modifier.isPublic(mod) && Modifier.isStatic(mod))                    break;            } catch (Exception e) {                //do nothing...            }        }                //添加简单类名与与类的映射        supplyBeanDictionary();                //执行获取到的方法并执行加工后的方法        System.out.println(clazz.getName() + ", " + method.getName());        MainAdvice main = new MainAdvice(clazz.newInstance(), method);        main.invoke();    }        /**     * 添加简单类名与与类的映射     */    private static void supplyBeanDictionary() {        //找出含有Service注解的类        Set<Class<?>> clazzes = ClassUtil.getClasses("yuki");//        Set<Class<?>> serviceClazzes = new LinkedHashSet<>();        for(Class<?> clazz : clazzes){//            System.out.println(clazz.isAnnotationPresent(Service.class));            if(clazz.getAnnotation(Service.class) != null){                AppContext.addBean(clazz);//                serviceClazzes.add(clazz);            }        }        /*for(Class<?> clazz : serviceClazzes){            System.out.println(clazz.getName());        }*/                //找到引用Service注解的类作为成员字段的类        /*for(Class<?> clazz : clazzes){            for(Field field : clazz.getDeclaredFields()){//                System.out.println(field.getName()+", "+field.getType());                for(Class<?> serviceClazz : serviceClazzes){                    if(Arrays.asList(serviceClazz.getInterfaces()).contains(field.getType())){//                        System.out.println(clazz.getSimpleName() + ": " + field.getName() + ", " + serviceClazz.getSimpleName());                    }                }            }        }*/    }}

/Annotation_Transaction/src/yuki/annotation/transaction/global/AppContext.java - version=NOT_END
这个类中执行getBean(String)方法时会抛出很多异常,我们把它单独放在一个方法里好了,
当然也可以对整个方法的方法体里的所有代码加上异常处理,其实我不太喜欢这样做,就这样吧
注意这里定义的静态泛型方法,泛型的类型参数是由接收它的返回值定义的
泛型不可以被继承,你造吗?因为泛型可能是终态类

package yuki.annotation.transaction.global;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.HashMap;import java.util.Map;/** * 储存简单类名与类的映射 * * @author yuki */public class AppContext {    private static Map<String, Class<?>> dictionary = new HashMap<>();    public static void addBean(Class<?> clazz){        String name = clazz.getSimpleName();//        System.out.println(clazz.getSimpleName() + ", " + clazz.getName());        if(dictionary.get(name) == null)            dictionary.put(name, clazz);    }        public static <T> T getBean(String name) {        T t = null;        try{            t = getBeanWithException(name);        }catch(Exception e){        }        return t;    }}

 


三、定义事务,产生生成服务类的动态代理
事务用单例显然是不合适的,但是这里就一个主线程访问这个事务,所以就让它单例吧
/Annotation_Transaction/src/yuki/annotation/transaction/global/Transaction.java - version=FINAL

package yuki.annotation.transaction.global;/** * 单例模式的事务 *  * http://cantellow.iteye.com/blog/838473 * 双重校验锁实现的单例模式 * @author yuki */public class Transaction {    //私有静态属性    private volatile static Transaction transaction;    //私有构造方法    private Transaction(){}    //双重校验锁    public static Transaction getTransaction(){        if(transaction == null)            //静态类的类作为同步锁            synchronized (Transaction.class) {                if(transaction == null)                    transaction = new Transaction();            }        return transaction;    }        private Boolean flag = false;    public void open(){        if(!flag){            System.out.println("事务开启中...");            flag = true;        }    }    public void close(){        if(flag){            System.out.println("事务关闭中...");            flag = false;        }    }}

动态代理注意在InvocationHandlerinvoke方法中的调用目标对象是方法外的final对象
/Annotation_Transaction/src/yuki/annotation/transaction/global/AppContext.java - version=FINAL

 

package yuki.annotation.transaction.global;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.HashMap;import java.util.Map;/** * 储存简单类名与类的映射 * * @author yuki */public class AppContext {    private static Map<String, Class<?>> dictionary = new HashMap<>();    public static void addBean(Class<?> clazz){        String name = clazz.getSimpleName();//        System.out.println(clazz.getSimpleName() + ", " + clazz.getName());        if(dictionary.get(name) == null)            dictionary.put(name, clazz);    }        public static <T> T getBean(String name) {        T t = null;        try{            t = getBeanWithException(name);        }catch(Exception e){        }        return t;    }        public static <T> T getBeanWithException(String name) throws Exception {//        return dictionary.get(name).newInstance();        Class<?> clazz = dictionary.get(name);        /*if(clazz == null)            throw new RuntimeException("找不到类");*/        /*if(clazz.isInterface())            throw new RuntimeException("找到的类是接口");*/        ClassLoader loader = Thread.currentThread().getContextClassLoader();        Class<?>[] interfaces = clazz.getInterfaces();        /*if(interfaces.length == 0)            throw new RuntimeException("找到的类没有接口");*/        final Object target = clazz.newInstance();        InvocationHandler h = new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                Object ret = null;                try {//                    System.out.println("正在执行方法:" + method.getName() + ", start");                    Transaction.getTransaction().open();                    ret = method.invoke(target, args);                    Transaction.getTransaction().close();//                    System.out.println("执行方法结束:" + method.getName() + ", end");                } catch (Exception e) {                }                return ret;            }        };        @SuppressWarnings("unchecked")        T t = (T)Proxy.newProxyInstance(loader, interfaces, h);        return t;    }}

 

 

 

下面是被代理的对象
/Annotation_Transaction/src/yuki/annotation/transaction/service/ProcessService.java - version=FINAL

package yuki.annotation.transaction.service;public interface ProcessService {    void process();}

/Annotation_Transaction/src/yuki/annotation/transaction/service/ProgressService.java - version=FINAL

package yuki.annotation.transaction.service;public interface ProgressService {    void progress();}

/Annotation_Transaction/src/yuki/annotation/transaction/service/ProcessServiceImp.java - version=FINAL

package yuki.annotation.transaction.service;import yuki.annotation.transaction.global.AppContext;import yuki.annotation.transaction.global.Service;@Servicepublic class ProcessServiceImp implements ProcessService {        private ProgressService progressService = AppContext.getBean(ProgressServiceImp.class.getSimpleName());    @Override    public void process() {        System.out.println("服务类正在处理:processing...");        progressService.progress();    }}

/Annotation_Transaction/src/yuki/annotation/transaction/service/ProgressServiceImp.java - version=FINAL

package yuki.annotation.transaction.service;import yuki.annotation.transaction.global.Service;@Servicepublic class ProgressServiceImp implements ProgressService {        @Override    public void progress() {        System.out.println("服务类正在处理:progressing...");    }}

/Annotation_Transaction/src/yuki/annotation/transaction/controller/Main.java - version=FINAL

package yuki.annotation.transaction.controller;import yuki.annotation.transaction.global.AppContext;import yuki.annotation.transaction.service.ProcessService;import yuki.annotation.transaction.service.ProcessServiceImp;/** * 自定义的主函数 * * @author yuki */public class Main {        public static void main() {        System.out.println("无参主方法执行中:main...");                //得到被赋予事务的代理对象        ProcessService processService = AppContext.getBean(ProcessServiceImp.class.getSimpleName());        processService.process();    }    }

运行结果如下:

yuki.annotation.transaction.controller.Main, main无参main方法执行前...无参主方法执行中:main...事务开启中...服务类正在处理:processing...服务类正在处理:progressing...事务关闭中...无参main方法执行后...

 

更多好文请查看:http://www.cnblogs.com/kodoyang/

点击下方的红色按钮 关注我 吧!

 

 

kodoyang

2014/10/1

 

模拟程序的入口与事务管理