自动注解实现Spring IOC和事务管理的示例分析

发布时间:2021-11-15 16:37:22 作者:柒染
来源:亿速云 阅读:131

自动注解实现Spring IOC和事务管理的示例分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

自定义注解实现spring的IOC以及事务管理功能

思路分析

IOC

IOC即控制反转,我们要把对象的创建通过注解来实现

事务管理功能

事务管理需要我们遵循事务的ACID原则

代码实现(只列出核心代码片段)

创建ApplicationContext接口

public interface ApplicationContext {
    
    Object getBean(String name);

    <T> T getBean(String name, Class<T> requiredType);
}

创建AnnotationConfigApplicationContext对象,实现接口方法  

  这是一个核心配置类,主要实现了以下三个功能

public class AnnotationConfigApplicationContext implements ApplicationContext {

    /**
     * 存放bean
     */
    private final Map<String, BeanDefinition> beanMap = new HashMap<>();

    /**
     * 先把包名转换为路径,首先得到项目的classpath
     */
    private final String CLASSPATH = this.getClass().getResource("/").getPath();

    public AnnotationConfigApplicationContext(String... basePackages) {
        try {
            scanPackages(basePackages);
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 扫描所有包 并实现bean对象的创建,依赖注入,增强事务
     * @param basePackages
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private void scanPackages(String[] basePackages) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        // 设置获取所有配置Service注解的对象
        setBeanDefinition(basePackages);
        // 设置依赖关系
        setBeanDepend();
        // 设置事务增强
        setTransaction();
    }

    /**
     * 获取所有需要管理的对象
     *
     * @param basePackages 需要扫描的包
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private void setBeanDefinition(String[] basePackages) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 获取所有类路径下的class文件
        List<String> classPaths = new ArrayList<>();
        for (String basePackage : basePackages) {
            //然后把我们的包名basPath转换为路径名
            basePackage = basePackage.replace(".", File.separator);
            //然后把classpath和basePack合并
            String searchPath = CLASSPATH + basePackage;
            getFile(classPaths, new File(searchPath));
        }
        // 找出所有有@Service注解的类,加入到beanMap中
        for (String s : classPaths) {
            s = s.replace(CLASSPATH, "").replace("/", ".").replace(".class", "");
            Class clazz = Class.forName(s);
            Service service = (Service) clazz.getAnnotation(Service.class);
            if (service != null) {
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanObject(clazz.newInstance());

                // 设置bean name
                String value = service.value();
                // 如果没有自定义bean name,设置bean name为class name
                if ("".equals(value)) {
                    value = clazz.getName();
                    value = value.substring(value.lastIndexOf(".") + 1);
                    value = value.substring(0, 1).toLowerCase() + value.substring(1);
                }
                beanDefinition.setBeanName(value);

                // 是否有依赖关系
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    declaredField.setAccessible(true);
                    Autowired autowired = declaredField.getAnnotation(Autowired.class);
                    // 如果类属性有@Autowired注解,把依赖对象放入BeanDefinition的dependBeanName集合中
                    if (autowired != null) {
                        beanDefinition.setAutoWired(true);
                        beanDefinition.getDependBeanName().add(declaredField.getName());
                    }
                }

                // 是否有父接口,为后面增强使用动态代理还是cglib代理做准备
                Class[] interfaces = clazz.getInterfaces();
                if (interfaces.length > 0) {
                    beanDefinition.setHaveParent(true);
                }

                // 是否有事务注解,如果有加入到BeanDefinition对象的transactionMethods属性中
                Annotation annotation = clazz.getAnnotation(Transactional.class);
                Method[] methods = clazz.getDeclaredMethods();
                //如果@Transactional注解出现在类上面,把类下所有的方法都加入到待添加事务的列表中
                if (annotation != null) {
                    for (Method method : methods) {
                        beanDefinition.getTransactionMethods().add(method);
                    }
                } else {
                    // 如果@Transactional在某个方法上面,把该方法加入到BeanDefinition对象的transactionMethods属性中
                    for (Method method : methods) {
                        Transactional methodAnnotation = method.getAnnotation(Transactional.class);
                        if (methodAnnotation != null) {
                            beanDefinition.getTransactionMethods().add(method);
                        }
                    }
                }
                // 将添加事务之后的对象重新加入到beanMap中
                beanMap.put(beanDefinition.getBeanName(), beanDefinition);
            }
        }
    }

    /**
     * 遍历所有bean,找出有依赖关系的bean,注入
     */
    private void setBeanDepend() {
        for (Map.Entry<String, BeanDefinition> next : beanMap.entrySet()) {
            BeanDefinition beanDefinition = next.getValue();
            //如果有AutoWired注解,设置值
            if (beanDefinition.isAutoWired()) {
                Object object = beanDefinition.getBeanObject();
                Class<?> definitionClass = object.getClass();
                List<String> beanNames = beanDefinition.getDependBeanName();
                beanNames.forEach(w -> {
                    try {
                        // 获取需要进行注入的对象
                        Field declaredField = definitionClass.getDeclaredField(w);
                        // 暴力访问
                        declaredField.setAccessible(true);
                        // 给依赖对象赋值
                        declaredField.set(object, getBean(w));
                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        e.printStackTrace();
                    }
                });
                // 组装好的对象重新放入map中
                beanMap.put(beanDefinition.getBeanName(), beanDefinition);
            }
        }
    }

    /**
     * 配置事务增强
     */
    private void setTransaction() {
        for (Map.Entry<String, BeanDefinition> next : beanMap.entrySet()) {
            BeanDefinition definition = next.getValue();
            //获取需要开启事务管理的类下的所有方法
            List<Method> transactionMethods = definition.getTransactionMethods();
            ProxyFactory proxyFactory = new ProxyFactory();
            // 根据代理对象是实现接口,来决定采用动态代理还是cglib代理
            if (!definition.isHaveParent()) {
                proxyFactory = new ProxyFactory(new CglibProxy());
            }
            //给方法配置事务增强
            Object withTransaction = proxyFactory.getProxyWithTransaction(definition.getBeanObject(), transactionMethods);
            definition.setBeanObject(withTransaction);
            //把增强之后的对象重新放入到beanMap中
            beanMap.put(next.getKey(), definition);
        }
    }

    private void getFile(List<String> classPaths, File file) {
        //文件夹递归
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File f1 : files) {
                    getFile(classPaths, f1);
                }
            }
        } else {
            //标准文件获取class文件
            if (file.getName().endsWith(Constant.FILE_TYPE_CLASS)) {
                //如果是class文件我们就放入我们的集合中。
                classPaths.add(file.getPath());
            }
        }
    }

    @Override
    public Object getBean(String name) {
        return beanMap.get(name).getBeanObject();
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) {
        Object o = beanMap.get(name).getBeanObject();
        if (o.getClass() == requiredType) {
            return (T) o;
        }
        return null;
    }
}

事务增强的实现

对于事务的增强,我们需要依赖代理来实现。代理我们使用了动态代理和cglib代理两种,对于需要代理对象实现接口的,我们使用动态代理;对于没有实现接口的对象,我们使用cglib代理。下面看下具体实现。

创建AopProxy接口
public interface AopProxy {

    /**
     * 创建带事务的代理
     *
     * @param o       代理对象
     * @param methods 代理对象中需要添加事务的方法
     * @return 增强之后的代理对象
     */
    abstract Object createProxyWithTransaction(Object o, List<Method> methods);
}
动态代理DynamicProxy的实现
public class DynamicProxy implements AopProxy {

    @Override
    public Object createProxyWithTransaction(Object o, List<Method> methods) {
        return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), (proxy, method, args) -> {
            Object invoke = null;
            boolean anyMatch = methods.stream().anyMatch(w -> w.getName().equals(method.getName()));
            if (anyMatch) {
                TransactionManager.getInstance().beginTransaction();
                try {
                    invoke = method.invoke(o, args);
                    TransactionManager.getInstance().commit();
                } catch (Exception e) {
                    TransactionManager.getInstance().rollback();
                    throw e;
                }
                return invoke;
            }
            invoke = method.invoke(o, args);
            return invoke;
        });
    }
}
cglib代理的实现
public class CglibProxy implements AopProxy {
    @Override
    public Object createProxyWithTransaction(Object o, List<Method> methods) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(o.getClass());
        enhancer.setCallback((MethodInterceptor) (o1, method, objects, methodProxy) -> {
            Object invoke;
            boolean anyMatch = methods.stream().anyMatch(w -> w.getName().equals(method.getName()));
            if (anyMatch) {
                TransactionManager.getInstance().beginTransaction();
                try {
                    invoke = method.invoke(o, objects);
                    TransactionManager.getInstance().commit();
                } catch (Exception e) {
                    TransactionManager.getInstance().rollback();
                    throw e;
                }
                return invoke;
            }
            invoke = method.invoke(o, objects);
            return invoke;
        });
        return enhancer.create();
    }

}

看完上述内容,你们掌握自动注解实现Spring IOC和事务管理的示例分析的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

推荐阅读:
  1. 程序员笔记|Spring IoC、面向切面编程、事务管理等Spring基本概念详解
  2. 详解Spring框架的核心思想之IOC

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring ioc

上一篇:XSS攻击有哪几种形态

下一篇:OAuth 2.0 的四种方式是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》