溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

自動(dòng)注解實(shí)現(xiàn)Spring IOC和事務(wù)管理的示例分析

發(fā)布時(shí)間:2021-11-15 16:37:22 來源:億速云 閱讀:123 作者:柒染 欄目:大數(shù)據(jù)

自動(dòng)注解實(shí)現(xiàn)Spring IOC和事務(wù)管理的示例分析,相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。

自定義注解實(shí)現(xiàn)spring的IOC以及事務(wù)管理功能

思路分析

IOC

IOC即控制反轉(zhuǎn),我們要把對象的創(chuàng)建通過注解來實(shí)現(xiàn)

  • @Service 類中聲明了@Service注解的對象,我們就對它的實(shí)例化進(jìn)行管理。(這里注解的名字無所謂,我們實(shí)現(xiàn)相應(yīng)的功能即可)

  • @Autowired 類中的屬性聲明了@Autowired注解的,我們就對該屬性進(jìn)行依賴注入   在程序運(yùn)行前,我們通過掃描所有的類文件,然后找出聲明了@Service注解的類,進(jìn)行實(shí)例化,然后加入到我們的一個(gè)Map集合中,同時(shí)查找該類中是否有聲明@Autowired注解的屬性,并進(jìn)行標(biāo)記。 再次遍歷聲明了@Service注解的類,然后注入聲明@Autowired注解屬性的類。這樣我們就把對象的創(chuàng)建以及依賴的注入完成了。

事務(wù)管理功能

事務(wù)管理需要我們遵循事務(wù)的ACID原則

  • @Transactional 類中或者方法中聲明了@Transactional注解的我們就要對改對象或者方法添加事務(wù)控制功能 首先我們先掃描所有類文件,找出聲明了@Transactional注解的類或者方法,準(zhǔn)備好一個(gè)List集合,如果注解聲明在類上,我們就把類中所有的方法放入集合中,如果注解是在方法上,我們直接把方法加入到List集合中。 然后我們通過代理(動(dòng)態(tài)代理或者cglib代理)給這些方法添加事務(wù)控制功能

代碼實(shí)現(xiàn)(只列出核心代碼片段)

創(chuàng)建ApplicationContext接口

public interface ApplicationContext {
    
    Object getBean(String name);

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

創(chuàng)建AnnotationConfigApplicationContext對象,實(shí)現(xiàn)接口方法  

  這是一個(gè)核心配置類,主要實(shí)現(xiàn)了以下三個(gè)功能

  • 獲取所有配置了@Service注解的類,并實(shí)例化,放入Map中

  • 對于類中添加@Autowired注解的屬性進(jìn)行依賴注入

  • 對于添加了@Transactional注解的屬性或者方法進(jìn)行事務(wù)增強(qiáng)

public class AnnotationConfigApplicationContext implements ApplicationContext {

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

    /**
     * 先把包名轉(zhuǎn)換為路徑,首先得到項(xiàng)目的classpath
     */
    private final String CLASSPATH = this.getClass().getResource("/").getPath();

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

    /**
     * 掃描所有包 并實(shí)現(xiàn)bean對象的創(chuàng)建,依賴注入,增強(qiáng)事務(wù)
     * @param basePackages
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private void scanPackages(String[] basePackages) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        // 設(shè)置獲取所有配置Service注解的對象
        setBeanDefinition(basePackages);
        // 設(shè)置依賴關(guān)系
        setBeanDepend();
        // 設(shè)置事務(wù)增強(qiáng)
        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轉(zhuǎn)換為路徑名
            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());

                // 設(shè)置bean name
                String value = service.value();
                // 如果沒有自定義bean name,設(shè)置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);

                // 是否有依賴關(guān)系
                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());
                    }
                }

                // 是否有父接口,為后面增強(qiáng)使用動(dòng)態(tài)代理還是cglib代理做準(zhǔn)備
                Class[] interfaces = clazz.getInterfaces();
                if (interfaces.length > 0) {
                    beanDefinition.setHaveParent(true);
                }

                // 是否有事務(wù)注解,如果有加入到BeanDefinition對象的transactionMethods屬性中
                Annotation annotation = clazz.getAnnotation(Transactional.class);
                Method[] methods = clazz.getDeclaredMethods();
                //如果@Transactional注解出現(xiàn)在類上面,把類下所有的方法都加入到待添加事務(wù)的列表中
                if (annotation != null) {
                    for (Method method : methods) {
                        beanDefinition.getTransactionMethods().add(method);
                    }
                } else {
                    // 如果@Transactional在某個(gè)方法上面,把該方法加入到BeanDefinition對象的transactionMethods屬性中
                    for (Method method : methods) {
                        Transactional methodAnnotation = method.getAnnotation(Transactional.class);
                        if (methodAnnotation != null) {
                            beanDefinition.getTransactionMethods().add(method);
                        }
                    }
                }
                // 將添加事務(wù)之后的對象重新加入到beanMap中
                beanMap.put(beanDefinition.getBeanName(), beanDefinition);
            }
        }
    }

    /**
     * 遍歷所有bean,找出有依賴關(guān)系的bean,注入
     */
    private void setBeanDepend() {
        for (Map.Entry<String, BeanDefinition> next : beanMap.entrySet()) {
            BeanDefinition beanDefinition = next.getValue();
            //如果有AutoWired注解,設(shè)置值
            if (beanDefinition.isAutoWired()) {
                Object object = beanDefinition.getBeanObject();
                Class<?> definitionClass = object.getClass();
                List<String> beanNames = beanDefinition.getDependBeanName();
                beanNames.forEach(w -> {
                    try {
                        // 獲取需要進(jìn)行注入的對象
                        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);
            }
        }
    }

    /**
     * 配置事務(wù)增強(qiáng)
     */
    private void setTransaction() {
        for (Map.Entry<String, BeanDefinition> next : beanMap.entrySet()) {
            BeanDefinition definition = next.getValue();
            //獲取需要開啟事務(wù)管理的類下的所有方法
            List<Method> transactionMethods = definition.getTransactionMethods();
            ProxyFactory proxyFactory = new ProxyFactory();
            // 根據(jù)代理對象是實(shí)現(xiàn)接口,來決定采用動(dòng)態(tài)代理還是cglib代理
            if (!definition.isHaveParent()) {
                proxyFactory = new ProxyFactory(new CglibProxy());
            }
            //給方法配置事務(wù)增強(qiáng)
            Object withTransaction = proxyFactory.getProxyWithTransaction(definition.getBeanObject(), transactionMethods);
            definition.setBeanObject(withTransaction);
            //把增強(qiáng)之后的對象重新放入到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 {
            //標(biāo)準(zhǔn)文件獲取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;
    }
}

事務(wù)增強(qiáng)的實(shí)現(xiàn)

對于事務(wù)的增強(qiáng),我們需要依賴代理來實(shí)現(xiàn)。代理我們使用了動(dòng)態(tài)代理和cglib代理兩種,對于需要代理對象實(shí)現(xiàn)接口的,我們使用動(dòng)態(tài)代理;對于沒有實(shí)現(xiàn)接口的對象,我們使用cglib代理。下面看下具體實(shí)現(xiàn)。

創(chuàng)建AopProxy接口
public interface AopProxy {

    /**
     * 創(chuàng)建帶事務(wù)的代理
     *
     * @param o       代理對象
     * @param methods 代理對象中需要添加事務(wù)的方法
     * @return 增強(qiáng)之后的代理對象
     */
    abstract Object createProxyWithTransaction(Object o, List<Method> methods);
}
動(dòng)態(tài)代理DynamicProxy的實(shí)現(xiàn)
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代理的實(shí)現(xiàn)
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();
    }

}

看完上述內(nèi)容,你們掌握自動(dòng)注解實(shí)現(xiàn)Spring IOC和事務(wù)管理的示例分析的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI