• 闭关修炼180天--手写IOC和AOP(xml篇)


    闭关修炼180天--手写IOC和AOP(xml篇)

    帝莘

    首先先分享一波思维导图,涵盖了一些Spring的知识点,当然这里并不全面,后期我会持续更新知识点。

    在手写实现IOC和AOP之前(也就是打造一个简单的Spring框架),先简单的了解一些Spring以及它的两个核心思想IOC和AOP的相关概念。

    Spring:

      概述:spring是分层的全栈轻量级开源框架,以ioc和AOP为内核,提供了展现层spring mvc和业务层管理等众多的企业应用技术,还能整合众多开源的第三方框架。

      优势:1.方便解耦,简化开发 2.AOP编程的支持 3.声明式事务的支持。4.方便程序的测试。5.方便集成各种优秀框架 6.降低javaEE API的使用难度。6.源码是经典的java学习案例。

      Spring 的核⼼结构:Spring是⼀个分层⾮常清晰并且依赖关系、职责定位⾮常明确的轻量级框架,主要包括⼏个⼤模块:数据处理模块、Web模块、AOP(Aspect Oriented Programming)/Aspects模块、

    Core Container模块和 Test 模块,如下图所示,Spring依靠这些基本模块,实现了⼀个令⼈愉悦的融合了现有解决⽅案的零侵⼊的轻量级框架。

    IOC: 

      IOC概念:控制反转,它是一个技术思想,不是一个技术实现,描述的事情是:java开发领域对象的创建,管理的问题。

      传统开发方式:比如A依赖于B,往往会在A中new一个B的对象。

      IOC思想下的开发方式:我们不用自己去new对象了,而是由IOC容器(Spring框架)去帮助我们实例化对象并且管理它,我们需要使用哪个对象,去问IOC容器要即可。我们丧失了一个权力(创建、管理对

    象的权力),得到了一个福利(不用考虑对象的创建、管理一系列事情)

      为什么叫控制反转?控制:指的是对象创建(实例化、管理)的权力;反转:控制权交给了外部环境(spring框架)

      IOC解决了什么问题:IOC解决了对象之间的耦合问题

      IOC和DI的区别?IOC是控制反转,DI是依赖注入

      怎么理解:IOC和DI描述的是一件事情(对象实例化及依赖关系维护这件事),不过角度不同。

      IOC是站在对象的角度,对象实例化及其管理的权力交给了(反转)容器。

      DI是站在容器的角度,容器会把对象依赖的其他对象注入(送过去),比如A对象实例化过程中因为声明了一个B类型的属性,那么就需要容器把B对象注入给A。

     

    手写Spring框架流程:

    实现思路:

    1. 编写xml文件,在根标签beans下条件bean,每一组bean对应一个需要加入容器管理的对象。
    2. 编写BeanFactory:解析xml文件,将解析出的一个个bean装载进map集合中,其中id为bean标签内id属性的值,value为根据bean标签内class属性的全路径值反射得到的目标类的实例对象。
    3. BeanFactory还要提供一个获取实例的方法getBean(String id)
    4. 为了添加不同类的依赖关系,在xml文件里面的bean标签组内添加property标签,其中property内的name属性的值是父标签所代表的类的set方法后面的名字,ref属性的值是它所依赖的对象的bean-id。在BeanFactory中进一步解析,把对应依赖关系添加进对象中,更新map。
    5. 配置事务,保证一个线程使用一个数据库连接,根据代理模式生产代理对象,根据代理对象回调用invoke方法的特性,在原方法前后增加事务增强,在这里,具体的事务管理我们交给TransactionManager类进行具体的管理,配置好代理类和事务管理类之间的依赖关系。

    代码实现:

      先看一下整体的项目结构:

      

      sql建表语句:

    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for users
    -- ----------------------------
    DROP TABLE IF EXISTS `users`;
    CREATE TABLE `users` (
      `id` int(11) NOT NULL,
      `username` varchar(255) COLLATE utf8_bin DEFAULT NULL,
      `balance` double(11,0) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    
    -- ----------------------------
    -- Records of users
    -- ----------------------------
    INSERT INTO `users` VALUES ('1', '汪苏泷', '1000');
    INSERT INTO `users` VALUES ('2', '薛之谦', '1000');

      几个pom依赖

    <!--dom4j-->
            <dependency>
                <groupId>dom4j</groupId>
                <artifactId>dom4j</artifactId>
                <version>1.6.1</version>
            </dependency>
            <dependency>
                <groupId>jaxen</groupId>
                <artifactId>jaxen</artifactId>
                <version>1.1.6</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.17</version>
            </dependency>
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.1.2</version>
            </dependency>
            <!--引入cglib依赖-->
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>2.1_2</version>
            </dependency>

       xml文件代码:bean.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <beans>
        <bean id="UserDao" class="com.radorm.spring.dao.impl.UserDaoImpl">
            <property name="ConnectionUtils" ref="ConnectionUtils"></property>
        </bean>
        <bean id="UserService" class="com.radorm.spring.service.impl.UserServiceImpl">
            <property name="UserDao" ref="UserDao"></property>
        </bean>
    
        <bean id="ConnectionUtils" class="com.radorm.spring.utils.ConnectionUtils"></bean>
    
        <bean id="TransactionManager" class="com.radorm.spring.utils.TransactionManager">
            <property name="ConnectionUtils" ref="ConnectionUtils"></property>
        </bean>
    
        <bean id="ProxyFactory" class="com.radorm.spring.factory.ProxyFactory">
            <property name="TransactionManager" ref="TransactionManager"></property>
        </bean>
    </beans>

      三个工具类:DataSourceUtils ConnectionUtils ,TransactionManager

    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import javax.sql.DataSource;
    import java.beans.PropertyVetoException;
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public class DataSourceUtils {
    
        private DataSourceUtils(){}
    
        private static DataSourceUtils dataSourceUtils = new DataSourceUtils();
    
        public static DataSourceUtils getInstance(){
            return dataSourceUtils;
        }
    
        public DataSource createDataSource(){
            //创建连接池
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            try {
                dataSource.setDriverClass("com.mysql.jdbc.Driver");
                dataSource.setJdbcUrl("jdbc:mysql:///mybatis");
                dataSource.setUser("root");
                dataSource.setPassword("root");
            } catch (PropertyVetoException e) {
                e.printStackTrace();
            }
            return dataSource;
        }
    
        public Connection getConnection(){
            DataSource dataSource = createDataSource();
            try {
                return dataSource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    import java.sql.Connection;
    
    public class ConnectionUtils {
        /**
         * 声明当前线程
         */
        private ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    
        /**
         * 获取当前线程里面的连接
         * @return
         */
        public Connection getLocalConnection(){
            Connection connection = threadLocal.get();
            if(connection == null){
                //如果在当前线程内获取不到连接,那就在线程池中获取,并且放到当前线程中
                connection = DataSourceUtils.getInstance().getConnection();
                threadLocal.set(connection);
            }
            return connection;
        }
    }
    import java.sql.SQLException;
    
    /**
     * 事务管理工厂
     */
    public class TransactionManager {
    
        private ConnectionUtils connectionUtils;
    
        public void setConnectionUtils(ConnectionUtils connectionUtils) {
            this.connectionUtils = connectionUtils;
        }
    
        public void beginTransaction() throws SQLException {
            connectionUtils.getLocalConnection().setAutoCommit(false);
        }
    
        public void commitTransaction() throws SQLException{
            connectionUtils.getLocalConnection().commit();
        }
    
        public void rollbackTransaction(){
            try {
                connectionUtils.getLocalConnection().rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

      两个工厂类:BeanFactory,ProxyFactory

    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import java.io.InputStream;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class BeanFactory {
    
        private static Map<String,Object> map = new HashMap<>();
    
        /**
         * 1.使用dom4j技术读取配置文件信息
         * 2.将读取到的对象以及key封装进map中
         * key = id,value = class反射产生的实例对象
         */
        static {
            //根据xml的路径加载为字节流到内存中
            InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
            SAXReader saxReader = new SAXReader();
            try {
                //读取该字节流为document
                Document document = saxReader.read(inputStream);
                //获取根标签下的元素
                Element rootElement = document.getRootElement();
                //获取根标签内部所有的bean标签里面的内容
                List<Element> beanList = rootElement.selectNodes("//bean");
                for (Element element : beanList) {
                    //根据属性名获取bean标签里面的内容
                    String id = element.attributeValue("id");
                    String aClass = element.attributeValue("class");
                    //利用反射技术根据全路径获取类对象
                    Class<?> aClass1 = Class.forName(aClass);
                    //根据类对象获取实例
                    Object o = aClass1.newInstance();
                    //组装map
                    map.put(id,o);
                }
                //获取所有的property
                List<Element> propertyList = rootElement.selectNodes("//property");
                for (Element element : propertyList) {
                    //获取property标签里面的属性值
                    String name = element.attributeValue("name");
                    String ref = element.attributeValue("ref");
    
                    //获取父标签
                    Element parentElement = element.getParent();
                    //获取父标签的id
                    String parentId = parentElement.attributeValue("id");
                    //根据父标签的id获取出父标签的实例化对象
                    Object parentObj = map.get(parentId);
                    //获取父对象想要添加依赖的实例化对象
                    Object refObj = map.get(ref);
                    //获取父对象的所有方法
                    Method[] methods = parentObj.getClass().getMethods();
                    for (Method method : methods) {
                        String methodName = method.getName();
                        //判断是否是set方法
                        if(methodName.equalsIgnoreCase("set"+name)){
                            //往方法中传入参数
                            method.invoke(parentObj,refObj);
                        }
                    }
                    //重新将父对象加入到map中
                    map.put(parentId,parentObj);
                }
            } catch (DocumentException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    
        public static <T> T getBean(String id){
            return (T) map.get(id);
        }
    }
    import com.radorm.spring.utils.TransactionManager;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * JDK动态代理工厂
     */
    public class ProxyFactory {
    
        private TransactionManager transactionManager;
    
        public void setTransactionManager(TransactionManager transactionManager) {
            this.transactionManager = transactionManager;
        }
    
    
        /**
         * jdk动态代理:要求被代理的对象实现了接口
         * @param object 委托对象
         * @param <T> 代理对象
         * @return
         */
        public <T> T getProxyJDK(Object object){
           Object result =  Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Object re = null;
                    try {
                        //开启事务
                        transactionManager.beginTransaction();
                        re = method.invoke(object,args);
                        //提交事务
                        transactionManager.commitTransaction();
                    } catch (Exception e) {
                        e.printStackTrace();
                        //回滚事务
                        transactionManager.rollbackTransaction();
                        throw e;
                    }
                    return re;
                }
            });
    
           return (T) result;
        }
    
    
        /**
         *  cglib动态代理
         * @param obj 委托对象
         * @param <T> 代理对象
         * @return
         */
        public <T> T getProxyCglib(Object obj){
            Object result = Enhancer.create(obj.getClass(), new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    Object od = null;
                    try {
                        //开启事务
                        transactionManager.beginTransaction();
                        od = method.invoke(obj,objects);
                        //提交事务
                        transactionManager.commitTransaction();
                    } catch (Exception e) {
                        e.printStackTrace();
                        //回滚事务
                        transactionManager.rollbackTransaction();
                        throw e;
                    }
                    return od;
                }
            });
            return (T) result;
        }
    }

      一个pojo:Users

    public class Users {
    
        private Integer id;
    
        private String username;
    
        private Double balance;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public Double getBalance() {
            return balance;
        }
    
        public void setBalance(Double balance) {
            this.balance = balance;
        }
    
        public Users(Integer id, String username, Double balance) {
            this.id = id;
            this.username = username;
            this.balance = balance;
        }
    }

      一个dao + 它的impl:UserDao + UserDaoImpl

    import com.radorm.spring.pojo.Users;
    
    public interface UserDao {
    
        void draw();
    
        Users select(Integer id);
    
        void updateUsers(Users users);
    }
    import com.radorm.spring.dao.UserDao;
    import com.radorm.spring.pojo.Users;
    import com.radorm.spring.utils.ConnectionUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class UserDaoImpl implements UserDao {
    
        private ConnectionUtils connectionUtils;
    
        public void setConnectionUtils(ConnectionUtils connectionUtils) {
            this.connectionUtils = connectionUtils;
        }
    
        @Override
        public void draw() {
            System.out.println("11111111");
        }
    
        @Override
        public Users select(Integer id) {
            Connection connection = connectionUtils.getLocalConnection();
            try {
                PreparedStatement preparedStatement = connection.prepareStatement("select * from users where id = ?");
                preparedStatement.setObject(1,id);
                ResultSet resultSet = preparedStatement.executeQuery();
                while (resultSet.next()){
                    int id1 = resultSet.getInt("id");
                    String username = resultSet.getString("username");
                    double balance = resultSet.getDouble("balance");
                    Users  users = new Users(id1,username,balance);
                    return users;
                }
    
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        public void updateUsers(Users users) {
            Connection localConnection = connectionUtils.getLocalConnection();
            try {
                PreparedStatement preparedStatement = localConnection.prepareStatement("update users set username = ?,balance = ? where id = ?");
                preparedStatement.setString(1,users.getUsername());
                preparedStatement.setDouble(2,users.getBalance());
                preparedStatement.setInt(3,users.getId());
                preparedStatement.executeUpdate();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
    
        }
    }

      一个service+它的impl:UserService,UserServiceImpl

    public interface UserService {
    
        void transfer(Integer fromId,Integer toId,Double money) throws Exception;
        
    }
    import com.radorm.spring.dao.UserDao;
    import com.radorm.spring.pojo.Users;
    import com.radorm.spring.service.UserService;
    
    public class UserServiceImpl implements UserService {
    
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public void transfer(Integer fromId, Integer toId, Double money) throws Exception {
    
    
                Users from = userDao.select(fromId);
    
                Users to = userDao.select(toId);
    
                from.setBalance(from.getBalance() - money);
    
                to.setBalance(to.getBalance() + money);
    
                userDao.updateUsers(from);
               //该异常代码可以选择打开或者关闭,检验事务的作用
               //int i = 1/0
    
                userDao.updateUsers(to);
         
    
        }
    }    

      test:BeanTest

    import com.radorm.spring.factory.ProxyFactory;
    import com.radorm.spring.service.UserService;
    import com.radorm.spring.factory.BeanFactory;
    import org.junit.Test;
    
    public class BeanTest {
    
        @Test
        public void test_bean(){
            ProxyFactory proxyFactory =  BeanFactory.getBean("ProxyFactory");
            UserService userService  = proxyFactory.getProxyJDK(BeanFactory.getBean("UserService"));
            try {
                userService.transfer(1,2,100d);
                System.out.println("转账成功");
            } catch (Exception e) {
                System.out.println("转账失败");
            }
        }
    }

    到此代码完成!

     我是Slience帝莘,期待与你的技术交流和思想碰撞。

  • 相关阅读:
    为什么Android的图片质量会比iPhone的差?
    第二次作业-编程
    印像最深的三位老师
    c++的类型转换(转)
    SpringMVC入门详解
    java基础
    springmvc
    Maven配置下载包速度更快
    spring中的bean.xml
    pom.xml依赖
  • 原文地址:https://www.cnblogs.com/zaevn00001/p/14162607.html
Copyright © 2020-2023  润新知