码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-10-01 22:31:51      阅读:254      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   使用   ar   java   

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

 

bubuko.com,布布扣
虚拟机访问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;

@Service
public 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;

@Service
public 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

 

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

标签:style   blog   http   color   io   os   使用   ar   java   

原文地址:http://www.cnblogs.com/kodoyang/p/Main_Annotation_Transaction.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!