精华内容
下载资源
问答
  • spring(纯手写spring)

    2018-08-03 19:26:23
    spring(纯手写spring),通过本代码,可以了解得到spring的基本原理。
  • 简单手写springIOC容器注解模式,仅供参考,欢迎指教。
  • 从零开始写 spring ioc 框架深学习 spring 源码 IoC 创作的 spring 的核 什么是 IOC 为什么需要 IOC 快速开始 maven 引 测试准备 执测试 spring 基本实现流程 说明 spring 核流程 BeanDefinition 的抽象 实现源码...
  • 手写spring mvc框架

    2020-09-22 10:48:04
    简单的模板spring mvc框架,实现了实例化controller、service,依赖注入等功能,可以下载学习一下,更加深入理解spring mvc框架
  • 通过对spring框架的理解和学习,手写一套属于自己的spring框架。这里面只是一个最简单的方式,真正的spring比这复杂的多。这里只是帮助喜欢spring的同学,对spring有个更深的理解和学习。
  • 手写Spring框架之AOP

    千次阅读 热门讨论 2019-01-25 15:35:30
    手写Spring框架第一篇博客(必读): 手写Spring框架 前面两篇博客已经实现了Bean容器, IOC功能和MVC功能, 本篇博客来实现AOP功能和事务管理. 在看下面的内容之前, 一定要先回顾下Spring AOP和动态代理. Spring AOP ...

    简介

    手写Spring框架第一篇博客(必读): 手写Spring框架

    前面两篇博客已经实现了Bean容器, IOC功能和MVC功能, 本篇博客来实现AOP功能和事务管理. 在看下面的内容之前, 一定要先回顾下Spring AOP和动态代理.

    Spring AOP

    动态代理

    handwritten-mvc-framwork 实现

    定义注解

    (1) 切面注解

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Aspect {
        /**
         * 包名
         */
        String pkg() default "";
    
        /**
         * 类名
         */
        String cls() default "";
    }
    

    (2) 事务注解

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Transactional {
    }
    

    搭建代理框架

    毫无疑问这个代理框架是基于动态代理实现的, 但加了一个链式代理的功能, 目的是为了解决多重代理的问题, 也就是目标对象的方法被多次增强.

    (1) Proxy接口

    我们自定义了一个最上层的代理接口, 其中doProxy()执行的是链式代理, 具体详情可以看后面的介绍.

    public interface Proxy {
    
        /**
         * 执行链式代理
         * 所谓链式代理, 就是说, 可将多个代理通过一条链子串起来, 一个个地去执行, 执行顺序取决于添加到链上的先后顺序
         */
        Object doProxy(ProxyChain proxyChain) throws Throwable;
    }
    

    (2) ProxyChain类

    这是一个代理链类, proxyList 存储的是代理列表(也就是增强列表), 当执行doProxyChain() 方法时会按照顺序执行增强, 最后再执行目标方法.

    public class ProxyChain {
    
        private final Class<?> targetClass; //目标类
        private final Object targetObject; //目标对象
        private final Method targetMethod; //目标方法
        private final MethodProxy methodProxy; //方法代理
        private final Object[] methodParams; //方法参数
    
        private List<Proxy> proxyList = new ArrayList<>(); //代理列表
        private int proxyIndex = 0; //代理索引
    
        public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
            this.targetClass = targetClass;
            this.targetObject = targetObject;
            this.targetMethod = targetMethod;
            this.methodProxy = methodProxy;
            this.methodParams = methodParams;
            this.proxyList = proxyList;
        }
    
        public Object[] getMethodParams() {
            return methodParams;
        }
    
        public Class<?> getTargetClass() {
            return targetClass;
        }
    
        public Method getTargetMethod() {
            return targetMethod;
        }
    
        /**
         * 递归执行
         */
        public Object doProxyChain() throws Throwable {
            Object methodResult;
            if (proxyIndex < proxyList.size()) {
                //执行增强方法
                methodResult = proxyList.get(proxyIndex++).doProxy(this);
            } else {
                //目标方法最后执行且只执行一次
                methodResult = methodProxy.invokeSuper(targetObject, methodParams);
            }
            return methodResult;
        }
    }
    

    (3) AspectProxy类

    AspectProxy是一个切面抽象类, 实现了Proxy接口, 类中定义了切入点判断和各种增强. 当执行 doProxy() 方法时, 会先进行切入点判断, 再执行前置增强, 代理链的下一个doProxyChain()方法, 后置增强等.

    public abstract class AspectProxy implements Proxy {
    
        private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);
    
        @Override
        public final Object doProxy(ProxyChain proxyChain) throws Throwable {
            Object result = null;
    
            Class<?> cls = proxyChain.getTargetClass();
            Method method = proxyChain.getTargetMethod();
            Object[] params = proxyChain.getMethodParams();
    
            begin();
            try {
                if (intercept(method, params)) {
                    before(method, params);
                    result = proxyChain.doProxyChain();
                    after(method, params);
                } else {
                    result = proxyChain.doProxyChain();
                }
            } catch (Exception e) {
                logger.error("proxy failure", e);
                error(method, params, e);
                throw e;
            } finally {
                end();
            }
    
            return result;
        }
    
        /**
         * 开始增强
         */
        public void begin() {
        }
    
        /**
         * 切入点判断
         */
        public boolean intercept(Method method, Object[] params) throws Throwable {
            return true;
        }
    
        /**
         * 前置增强
         */
        public void before(Method method, Object[] params) throws Throwable {
        }
    
        /**
         * 后置增强
         */
        public void after(Method method, Object[] params) throws Throwable {
        }
    
        /**
         * 异常增强
         */
        public void error(Method method, Object[] params, Throwable e) {
        }
    
        /**
         * 最终增强
         */
        public void end() {
        }
    }
    

    (4) ProxyFactory类

    这是一个代理工厂类, 我们通过这个类来梳理上面的代理逻辑. 当调用 ProxyFactory.createProxy(final Class<?> targetClass, final List proxyList) 方法来创建一个代理对象后, 每次执行代理方法时都会调用 intercept() 方法, 从而创建一个 ProxyChain 对象, 并调用该对象的 doProxyChain() 方法. 调用doProxyChain()方法时会首先递归的执行增强, 最后再执行目标方法.

    public class ProxyFactory {
    
        /**
         * 输入一个目标类和一组Proxy接口实现, 输出一个代理对象
         */
        @SuppressWarnings("unchecked")
        public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList) {
            return (T) Enhancer.create(targetClass, new MethodInterceptor() {
                /**
                 * 代理方法, 每次调用目标方法时都会先创建一个 ProxyChain 对象, 然后调用该对象的 doProxyChain() 方法.
                 */
                @Override
                public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
                    return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList).doProxyChain();
                }
            });
        }
    }
    

    (5) AopHelper 助手类

    AopHelper 助手类用来初始化整个AOP框架, 逻辑如下:

    框架中所有Bean的实例都是从Bean容器中获取, 然后再执行该实例的方法, 基于此, 初始化AOP框架实际上就是用代理对象覆盖掉Bean容器中的目标对象, 这样根据目标类的Class对象从Bean容器中获取到的就是代理对象, 从而达到了对目标对象增强的目的.

    public final class AopHelper {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);
    
        static {
            try {
                //切面类-目标类集合的映射
                Map<Class<?>, Set<Class<?>>> aspectMap = createAspectMap();
                //目标类-切面对象列表的映射
                Map<Class<?>, List<Proxy>> targetMap = createTargetMap(aspectMap);
                //把切面对象织入到目标类中, 创建代理对象
                for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
                    Class<?> targetClass = targetEntry.getKey();
                    List<Proxy> proxyList = targetEntry.getValue();
                    Object proxy = ProxyFactory.createProxy(targetClass, proxyList);
                    //覆盖Bean容器里目标类对应的实例, 下次从Bean容器获取的就是代理对象了
                    BeanHelper.setBean(targetClass, proxy);
                }
            } catch (Exception e) {
                LOGGER.error("aop failure", e);
            }
        }
    
        /**
         * 获取切面类-目标类集合的映射
         */
        private static Map<Class<?>, Set<Class<?>>> createAspectMap() throws Exception {
            Map<Class<?>, Set<Class<?>>> aspectMap = new HashMap<Class<?>, Set<Class<?>>>();
            addAspectProxy(aspectMap);
            return aspectMap;
        }
    
        /**
         *  获取普通切面类-目标类集合的映射
         */
        private static void addAspectProxy(Map<Class<?>, Set<Class<?>>> aspectMap) throws Exception {
            //所有实现了AspectProxy抽象类的切面
            Set<Class<?>> aspectClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
            for (Class<?> aspectClass : aspectClassSet) {
                if (aspectClass.isAnnotationPresent(Aspect.class)) {
                    Aspect aspect = aspectClass.getAnnotation(Aspect.class);
                    //与该切面对应的目标类集合
                    Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
                    aspectMap.put(aspectClass, targetClassSet);
                }
            }
        }
    
        /**
         * 根据@Aspect定义的包名和类名去获取对应的目标类集合
         */
        private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception {
            Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
            // 包名
            String pkg = aspect.pkg();
            // 类名
            String cls = aspect.cls();
            // 如果包名与类名均不为空,则添加指定类
            if (!pkg.equals("") && !cls.equals("")) {
                targetClassSet.add(Class.forName(pkg + "." + cls));
            } else if (!pkg.equals("")) {
                // 如果包名不为空, 类名为空, 则添加该包名下所有类
                targetClassSet.addAll(ClassUtil.getClassSet(pkg));
            }
            return targetClassSet;
        }
    
        /**
         * 将切面类-目标类集合的映射关系 转化为 目标类-切面对象列表的映射关系
         */
        private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> aspectMap) throws Exception {
            Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
            for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : aspectMap.entrySet()) {
                //切面类
                Class<?> aspectClass = proxyEntry.getKey();
                //目标类集合
                Set<Class<?>> targetClassSet = proxyEntry.getValue();
                //创建目标类-切面对象列表的映射关系
                for (Class<?> targetClass : targetClassSet) {
                    //切面对象
                    Proxy aspect = (Proxy) aspectClass.newInstance();
                    if (targetMap.containsKey(targetClass)) {
                        targetMap.get(targetClass).add(aspect);
                    } else {
                        //切面对象列表
                        List<Proxy> aspectList = new ArrayList<Proxy>();
                        aspectList.add(aspect);
                        targetMap.put(targetClass, aspectList);
                    }
                }
            }
            return targetMap;
        }
    }
    

    (6) HelperLoader 类

    在手写Spring之MVC这篇博客里我们定义了这个类, 目的是为了集中加载 ClassHelper, BeanHelper, IocHelper, ControllerHelper 这四个助手类, 这里还要再加上个 AopHelper 类.

    public final class HelperLoader {
        public static void init() {
            Class<?>[] classList = {
                ClassHelper.class,
                BeanHelper.class,
                AopHelper.class,
                IocHelper.class,
                ControllerHelper.class
            };
            for (Class<?> cls : classList) {
                ClassUtil.loadClass(cls.getName());
            }
        }
    }
    

    AOP实例

    我们创建一个监控接口性能的切面, 当接口被调用后, 打印接口的执行时间.

    (1) 业务类

    public interface IUserService {
        List<User> getAllUser();
    }
    
    @Service
    public class UserService implements IUserService {
        /**
         * 获取所有用户
         */
        public List<User> getAllUser() {
            List<User> userList = new ArrayList<>();
            userList.add(new User(1, "Tom", 22));
            userList.add(new User(2, "Alic", 12));
            userList.add(new User(3, "Bob", 32));
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return userList;
        }
    }
    

    (2) 处理器

    @Controller
    public class UserController {
        @Autowired
        private IUserService userService;
    
        /**
         * 用户列表
         * @return
         */
        @RequestMapping(value = "/userList", method = RequestMethod.GET)
        public View getUserList() {
            List<User> userList = userService.getAllUser();
            return new View("index.jsp").addModel("userList", userList);
        }
    }
    

    (3) 接口性能监控切面

    目标类是 com.tyshawn.controller 包下的 UserController, 切入点是 getUserList() 方法. 日志记录切入点方法的执行时间.

    @Aspect(pkg = "com.tyshawn.controller", cls = "UserController")
    public class EfficientAspect extends AspectProxy {
        private static final Logger LOGGER = LoggerFactory.getLogger(EfficientAspect.class);
    
        private long begin;
    
        /**
         * 切入点判断
         */
        @Override
        public boolean intercept(Method method, Object[] params) throws Throwable {
            return method.getName().equals("getUserList");
        }
    
        @Override
        public void before(Method method, Object[] params) throws Throwable {
            LOGGER.debug("---------- begin ----------");
            begin = System.currentTimeMillis();
        }
    
        @Override
        public void after(Method method, Object[] params) throws Throwable {
            LOGGER.debug(String.format("time: %dms", System.currentTimeMillis() - begin));
            LOGGER.debug("----------- end -----------");
        }
    }
    

    (4) 结果

    http://localhost:8081/handwritten/userList
    
    ---------- begin ----------
    time: 1001ms
    ----------- end -----------
    

    事务管理

    我们要达到的目的是, 当我们在目标方法上加 @Transactional 注解后, 该方法就拥有了事务管理. 用AOP实现的思路就是, 前置增强为开启事务, 后置增强为提交事务, 异常增强为回滚事务.

    (1) DatabaseHelper 助手类

    DatabaseHelper 为数据库操作助手类, 可以通过该助手类进行增删改查, 事务等一系列的数据库操作.

    public final class DatabaseHelper {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelper.class);
    
        private static final ThreadLocal<Connection> CONNECTION_HOLDER;
    
        private static final QueryRunner QUERY_RUNNER;
    
        private static final BasicDataSource DATA_SOURCE;
    
        static {
            CONNECTION_HOLDER = new ThreadLocal<Connection>();
    
            QUERY_RUNNER = new QueryRunner();
    
            DATA_SOURCE = new BasicDataSource();
            DATA_SOURCE.setDriverClassName(ConfigHelper.getJdbcDriver());
            DATA_SOURCE.setUrl(ConfigHelper.getJdbcUrl());
            DATA_SOURCE.setUsername(ConfigHelper.getJdbcUsername());
            DATA_SOURCE.setPassword(ConfigHelper.getJdbcPassword());
        }
    
        /**
         * 获取数据源
         */
        public static DataSource getDataSource() {
            return DATA_SOURCE;
        }
    
        /**
         * 获取数据库连接
         */
        public static Connection getConnection() {
            Connection conn = CONNECTION_HOLDER.get();
            if (conn == null) {
                try {
                    conn = DATA_SOURCE.getConnection();
                } catch (SQLException e) {
                    LOGGER.error("get connection failure", e);
                    throw new RuntimeException(e);
                } finally {
                    CONNECTION_HOLDER.set(conn);
                }
            }
            return conn;
        }
    
        /**
         * 开启事务
         */
        public static void beginTransaction() {
            Connection conn = getConnection();
            if (conn != null) {
                try {
                    conn.setAutoCommit(false);
                } catch (SQLException e) {
                    LOGGER.error("begin transaction failure", e);
                    throw new RuntimeException(e);
                } finally {
                    CONNECTION_HOLDER.set(conn);
                }
            }
        }
    
        /**
         * 提交事务
         */
        public static void commitTransaction() {
            Connection conn = getConnection();
            if (conn != null) {
                try {
                    conn.commit();
                    conn.close();
                } catch (SQLException e) {
                    LOGGER.error("commit transaction failure", e);
                    throw new RuntimeException(e);
                } finally {
                    CONNECTION_HOLDER.remove();
                }
            }
        }
    
        /**
         * 回滚事务
         */
        public static void rollbackTransaction() {
            Connection conn = getConnection();
            if (conn != null) {
                try {
                    conn.rollback();
                    conn.close();
                } catch (SQLException e) {
                    LOGGER.error("rollback transaction failure", e);
                    throw new RuntimeException(e);
                } finally {
                    CONNECTION_HOLDER.remove();
                }
            }
        }
    
        /**
         * 查询实体
         */
        public static <T> T queryEntity(Class<T> entityClass, String sql, Object... params) {
            T entity;
            try {
                Connection conn = getConnection();
                entity = QUERY_RUNNER.query(conn, sql, new BeanHandler<T>(entityClass), params);
            } catch (SQLException e) {
                LOGGER.error("query entity failure", e);
                throw new RuntimeException(e);
            }
            return entity;
        }
    
        /**
         * 查询实体列表
         */
        public static <T> List<T> queryEntityList(Class<T> entityClass, String sql, Object... params) {
            List<T> entityList;
            try {
                Connection conn = getConnection();
                entityList = QUERY_RUNNER.query(conn, sql, new BeanListHandler<T>(entityClass), params);
            } catch (SQLException e) {
                LOGGER.error("query entity list failure", e);
                throw new RuntimeException(e);
            }
            return entityList;
        }
    
        /**
         * 执行更新语句(包括:update、insert、delete)
         */
        public static int update(String sql, Object... params) {
            int rows;
            try {
                Connection conn = getConnection();
                rows = QUERY_RUNNER.update(conn, sql, params);
            } catch (SQLException e) {
                LOGGER.error("execute update failure", e);
                throw new RuntimeException(e);
            }
            return rows;
        }
    
        /**
         * 插入实体
         */
        public static <T> boolean insertEntity(Class<T> entityClass, Map<String, Object> fieldMap) {
            if (MapUtils.isEmpty(fieldMap)) {
                LOGGER.error("can not insert entity: fieldMap is empty");
                return false;
            }
    
            String sql = "INSERT INTO " + entityClass.getSimpleName();
            StringBuilder columns = new StringBuilder("(");
            StringBuilder values = new StringBuilder("(");
            for (String fieldName : fieldMap.keySet()) {
                columns.append(fieldName).append(", ");
                values.append("?, ");
            }
            columns.replace(columns.lastIndexOf(", "), columns.length(), ")");
            values.replace(values.lastIndexOf(", "), values.length(), ")");
            sql += columns + " VALUES " + values;
    
            Object[] params = fieldMap.values().toArray();
    
            return update(sql, params) == 1;
        }
    
        /**
         * 更新实体
         */
        public static <T> boolean updateEntity(Class<T> entityClass, long id, Map<String, Object> fieldMap) {
            if (MapUtils.isEmpty(fieldMap)) {
                LOGGER.error("can not update entity: fieldMap is empty");
                return false;
            }
    
            String sql = "UPDATE " + entityClass.getSimpleName() + " SET ";
            StringBuilder columns = new StringBuilder();
            for (String fieldName : fieldMap.keySet()) {
                columns.append(fieldName).append(" = ?, ");
            }
            sql += columns.substring(0, columns.lastIndexOf(", ")) + " WHERE id = ?";
    
            List<Object> paramList = new ArrayList<Object>();
            paramList.addAll(fieldMap.values());
            paramList.add(id);
            Object[] params = paramList.toArray();
    
            return update(sql, params) == 1;
        }
    
        /**
         * 删除实体
         */
        public static <T> boolean deleteEntity(Class<T> entityClass, long id) {
            String sql = "DELETE FROM " + entityClass.getSimpleName() + " WHERE id = ?";
            return update(sql, id) == 1;
        }
    }
    

    (2) TransactionProxy 类

    TransactionProxy 为事务切面类, 同样实现了Proxy接口, 其 doProxy() 方法就是先判断代理方法上有没有 @Transactional 注解, 如果有就加上事务管理, 没有就直接执行.

    public class TransactionProxy implements Proxy {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(TransactionProxy.class);
    
        @Override
        public Object doProxy(ProxyChain proxyChain) throws Throwable {
            Object result;
            Method method = proxyChain.getTargetMethod();
            //加了@Transactional注解的方法要做事务处理
            if (method.isAnnotationPresent(Transactional.class)) {
                try {
                    DatabaseHelper.beginTransaction();
                    LOGGER.debug("begin transaction");
                    result = proxyChain.doProxyChain();
                    DatabaseHelper.commitTransaction();
                    LOGGER.debug("commit transaction");
                } catch (Exception e) {
                    DatabaseHelper.rollbackTransaction();
                    LOGGER.debug("rollback transaction");
                    throw e;
                }
            } else {
                result = proxyChain.doProxyChain();
            }
            return result;
        }
    }
    

    (3) AopHelper 助手类

    在前面的AOP部分我们已经知道了 AopHelper 的作用以及实现逻辑, 事务代理相比普通代理的差别是, 我们默认所有Service对象都被代理了, 也就是说通过Service的Class对象, 从Bean容器中得到的都是代理对象, 我们在执行代理方法时会判断目标方法上是否存在 @Transactional 注解, 有就加上事务管理, 没有就直接执行, 如上面的代码 TransactionProxy.doProxy().

    public final class AopHelper {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);
    
        static {
            try {
                //切面类-目标类集合的映射
                Map<Class<?>, Set<Class<?>>> aspectMap = createAspectMap();
                //目标类-切面对象列表的映射
                Map<Class<?>, List<Proxy>> targetMap = createTargetMap(aspectMap);
                //把切面对象织入到目标类中, 创建代理对象
                for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
                    Class<?> targetClass = targetEntry.getKey();
                    List<Proxy> proxyList = targetEntry.getValue();
                    Object proxy = ProxyFactory.createProxy(targetClass, proxyList);
                    //覆盖Bean容器里目标类对应的实例, 下次从Bean容器获取的就是代理对象了
                    BeanHelper.setBean(targetClass, proxy);
                }
            } catch (Exception e) {
                LOGGER.error("aop failure", e);
            }
        }
    
        /**
         * 获取切面类-目标类集合的映射
         */
        private static Map<Class<?>, Set<Class<?>>> createAspectMap() throws Exception {
            Map<Class<?>, Set<Class<?>>> aspectMap = new HashMap<Class<?>, Set<Class<?>>>();
            addAspectProxy(aspectMap);
            addTransactionProxy(aspectMap);
            return aspectMap;
        }
    
        /**
         *  获取普通切面类-目标类集合的映射
         */
        private static void addAspectProxy(Map<Class<?>, Set<Class<?>>> aspectMap) throws Exception {
            //所有实现了AspectProxy抽象类的切面
            Set<Class<?>> aspectClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
            for (Class<?> aspectClass : aspectClassSet) {
                if (aspectClass.isAnnotationPresent(Aspect.class)) {
                    Aspect aspect = aspectClass.getAnnotation(Aspect.class);
                    //与该切面对应的目标类集合
                    Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
                    aspectMap.put(aspectClass, targetClassSet);
                }
            }
        }
    
        /**
         *  获取事务切面类-目标类集合的映射
         */
        private static void addTransactionProxy(Map<Class<?>, Set<Class<?>>> aspectMap) {
            Set<Class<?>> serviceClassSet = ClassHelper.getClassSetByAnnotation(Service.class);
            aspectMap.put(TransactionProxy.class, serviceClassSet);
        }
    
        /**
         * 根据@Aspect定义的包名和类名去获取对应的目标类集合
         */
        private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception {
            Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
            // 包名
            String pkg = aspect.pkg();
            // 类名
            String cls = aspect.cls();
            // 如果包名与类名均不为空,则添加指定类
            if (!pkg.equals("") && !cls.equals("")) {
                targetClassSet.add(Class.forName(pkg + "." + cls));
            } else if (!pkg.equals("")) {
                // 如果包名不为空, 类名为空, 则添加该包名下所有类
                targetClassSet.addAll(ClassUtil.getClassSet(pkg));
            }
            return targetClassSet;
        }
    
        /**
         * 将切面类-目标类集合的映射关系 转化为 目标类-切面对象列表的映射关系
         */
        private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> aspectMap) throws Exception {
            Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
            for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : aspectMap.entrySet()) {
                //切面类
                Class<?> aspectClass = proxyEntry.getKey();
                //目标类集合
                Set<Class<?>> targetClassSet = proxyEntry.getValue();
                //创建目标类-切面对象列表的映射关系
                for (Class<?> targetClass : targetClassSet) {
                    //切面对象
                    Proxy aspect = (Proxy) aspectClass.newInstance();
                    if (targetMap.containsKey(targetClass)) {
                        targetMap.get(targetClass).add(aspect);
                    } else {
                        //切面对象列表
                        List<Proxy> aspectList = new ArrayList<Proxy>();
                        aspectList.add(aspect);
                        targetMap.put(targetClass, aspectList);
                    }
                }
            }
            return targetMap;
        }
    }
    

    事务管理实例

    (1) 业务类

    public interface IUserService {
        List<User> getAllUser();
    
        User GetUserInfoById(Integer id);
    
        boolean updateUser(int id, Map<String, Object> fieldMap);
    }
    
    @Service
    public class UserService implements IUserService {
        /**
         * 获取所有用户
         */
        public List<User> getAllUser() {
            String sql = "SELECT * FROM user";
            return DatabaseHelper.queryEntityList(User.class, sql);
        }
    
        /**
         * 根据id获取用户信息
         */
        public User GetUserInfoById(Integer id) {
            String sql = "SELECT * FROM user WHERE id = ?";
            return DatabaseHelper.queryEntity(User.class, sql, id);
        }
    
        /**
         * 修改用户信息
         */
        @Transactional
        public boolean updateUser(int id, Map<String, Object> fieldMap) {
            return DatabaseHelper.updateEntity(User.class, id, fieldMap);
        }
    }
    

    (2) 处理器

    @Controller
    public class UserController {
        @Autowired
        private IUserService userService;
    
        /**
         * 用户列表
         *
         * @return
         */
        @RequestMapping(value = "/userList", method = RequestMethod.GET)
        public View getUserList() {
            List<User> userList = userService.getAllUser();
            return new View("index.jsp").addModel("userList", userList);
        }
    
        /**
         * 用户详情
         *
         * @param param
         * @return
         */
        @RequestMapping(value = "/userInfo", method = RequestMethod.GET)
        public Data getUserInfo(Param param) {
            String id = (String) param.getParamMap().get("id");
            User user = userService.GetUserInfoById(Integer.parseInt(id));
    
            return new Data(user);
        }
    
        @RequestMapping(value = "/userEdit", method = RequestMethod.GET)
        public Data editUser(Param param) {
            String id = (String) param.getParamMap().get("id");
            Map<String, Object> fieldMap = new HashMap<>();
            fieldMap.put("age", 911);
            userService.updateUser(Integer.parseInt(id), fieldMap);
    
            return new Data("Success.");
        }
    }
    

    (3) JSP页面

    <%@ page pageEncoding="UTF-8" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <c:set var="BASE" value="${pageContext.request.contextPath}"/>
    <html>
    <head>
        <title>用户信息</title>
    </head>
    <body>
    <h1>用户信息</h1>
    <table>
        <tr>
            <th>用户id</th>
            <th>名称</th>
            <th>年龄</th>
        </tr>
        <c:forEach var="userinfo" items="${userList}">
            <tr>
                <td>${userinfo.id}</td>
                <td>${userinfo.name}</td>
                <td>${userinfo.age}</td>
                <td>
                    <a href="${BASE}/userInfo?id=${userinfo.id}">详情</a>
                    <a href="${BASE}/userEdit?id=${userinfo.id}">编辑</a>
                </td>
            </tr>
        </c:forEach>
    </table>
    </body>
    </html>
    

    (4) 结果

    http://localhost:8081/handwritten/userList
    在这里插入图片描述

    点击编辑, 控制台打印: 
    begin transaction
    commit transaction
    

    结束

    到此为止, handwritten-mvc-framwork 框架的所有功能都已实现, 包括Bean容器, IOC, MVC, AOP, 事务管理, 大家可以多看看源代码, 思路理顺之后一定会收获良多.

    展开全文
  • 手写Spring框架

    万次阅读 多人点赞 2019-01-25 15:30:05
    在学习完Spring框架之后, 我们知道了 Spring容器, IOC, AOP, 事务管理, SpringMVC 这些Spring的核心内容, 也知道了它们底层实现的基本原理, 比如Spring容器就是个Map映射, IOC底层就是反射机制, AOP底层是动态代理, ...

    在学习完Spring框架之后, 我们知道了 Spring容器, IOC, AOP, 事务管理, SpringMVC 这些Spring的核心内容, 也知道了它们底层实现的基本原理, 比如Spring容器就是个Map映射, IOC底层就是反射机制, AOP底层是动态代理, SpringMVC不就是对Servlet进行了下封装嘛! 哈哈, 当然这些只是些皮毛, Spring除此之外还有更加复杂的设计, 但我们完全可以抛弃那些复杂的设计, 通过这些底层原理自己来写个Spring框架. 写完之后, 相信我们会对Spring框架有个更加深刻的理解.

    前置知识

    在自己动手写Spring框架之前, 我们得先了解下Spring框架的核心知识点, 如下:

    Spring基础

    Spring AOP

    Spring事务管理

    Spring MVC

    Java反射机制

    动态代理

    Java注解

    代码下载

    在开始动手写博客之前, 我已经完成了自己的Spring框架, 并给它取名为 handwritten-mvc-framwork, GitHub地址为:
    https://github.com/tyshawnlee/handwritten-mvc.git

    大家可以 clone 到自己的IDE中, 然后跟着下面的博客我们一起学习.

    项目导入后结构如下:
    在这里插入图片描述

    其中, handwritten-mvc-framwork 为自己实现的Spring框架, handwritten-mvc-example 为该框架的实例.

    开始

    (1) 建立框架

    我们首先创建一个Maven项目, 取名为 handwritten-mvc-framwork, 我们尽可能少的使用第三方依赖, 精简后的依赖如下:

    <dependencies>
        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- JSP -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>
        <!-- JSP标准标签库 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>runtime</scope>
        </dependency>
        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.33</version>
            <scope>runtime</scope>
        </dependency>
        <!--数据库连接池-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.0.1</version>
        </dependency>
        <!--JDBC工具类库-->
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.6</version>
        </dependency>
        <!-- 日志框架 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
        <!-- 动态代理依赖 -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!-- 通用工具包 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!--集合工具包-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.0</version>
        </dependency>
        <!--JSON依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.49</version>
        </dependency>
    </dependencies>
    

    (2) 实现Spring容器和IOC

    手写Spring框架之IOC

    (3) 实现Spring MVC

    手写Spring框架之MVC

    (4) 实现Spring AOP和事务管理

    手写Spring框架之AOP

    展开全文
  • Spring(一)300行代码手写Spring初体验Mini版Spring实现思路300行代码实现代码目录结构1、配置阶段application.properties文件web.xml文件自定义注解DispatcherServlet,继承重写三个方法2、初始化阶段,重写init...

    Mini版Spring实现思路

    在这里插入图片描述

    300行代码实现

    代码目录结构

    在这里插入图片描述

    1、配置阶段

    application.properties文件

    // 扫描路径
    scanPackage=com.test.demo
    

    web.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
      <display-name>test Web Application</display-name>
      <servlet>
        <servlet-name>testmvc</servlet-name>
        <servlet-class>com.test.mvcframework.v1.TestDispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>application.properties</param-value>
    
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>testmvc</servlet-name>
        <url-pattern>/*</url-pattern>
      </servlet-mapping>
    </web-app>
    

    自定义注解

    在这里插入图片描述
    这里只举一个例子

    
    package com.test.mvcframework.annotation;
    
    import java.lang.annotation.*;
    
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface TestAutowired {
        String value() default "";
    }
    

    DispatcherServlet,继承重写三个方法

    doPost();
    doGet();
    init();

    @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            try {
                doDispatch(req, resp);
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                resp.getWriter().write("500");
            }
        }
    @Override
        public void init(ServletConfig config) throws ServletException {
    
        }
    

    2、初始化阶段,重写init方法

     @Override
        public void init(ServletConfig config) throws ServletException {
            //1、加载配置文件
            doLoadConfig(config.getInitParameter("contextConfigLocation"));
    
            //2、扫描相关的类
            doScanner(contextConfig.getProperty("scanPackage"));
    
            //IOC
            //3、初始化扫描到的类,放入IoC容器
            doInstance();
            
            //AOP位置
            
    		//DI
            //4、依赖注入
            doAutowired();
            
    		//MVC
            //5、初始化HandlerMapping
            initHandlerMapping();
        }
        
        private void initHandlerMapping() {
            //判断ioc容器是否为空
            if (ioc.isEmpty()) {
                return;
            }
    
            for (Map.Entry<String, Object> entry : ioc.entrySet()) {
                Class<?> clazz = entry.getValue().getClass();
    
                if (!clazz.isAnnotationPresent(TestController.class)) {
                    continue;
                }
    
                //保存写在类上面的@TestRuquestMapping("/demo")
                String baseUrl = "";
                if (clazz.isAnnotationPresent(TestRequestMapping.class)) {
                    TestRequestMapping requestMapping = clazz.getAnnotation(TestRequestMapping.class);
                    baseUrl = requestMapping.value();
                }
    
                //默认获取所有的public方法
                for (Method method : clazz.getMethods()) {
                    if (!method.isAnnotationPresent(TestRequestMapping.class)) {
                        continue;
                    }
    
                    TestRequestMapping requestMapping = method.getAnnotation(TestRequestMapping.class);
                    //优化,/问题
                    String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
                    handlerMapping.put(url, method);
                    System.out.println(url + "::::::::::::::::" + method);
                }
            }
    
        }
    
        private void doInstance() {
            //判断文件名是否为空
            if (classNames.isEmpty()) {
                return;
            }
    
            for (String className : classNames) {
                try {
                    Class<?> clazz = Class.forName(className);
    
                    //加了注解的类才需要初始化
                    //以@Controller 和@Service 为例,@Componment 不举例子了
                    if (clazz.isAnnotationPresent(TestController.class)) {
                        Object instance = clazz.newInstance();
                        //Spring 默认类名首字母小写
                        String beanName = toLowerFirstCase(clazz.getSimpleName());
                        //放入IoC容器,key为文件名,值为bean
                        ioc.put(beanName, instance);
                    } else if (clazz.isAnnotationPresent(TestService.class)) {
                        //1、自定义的beanName
                        TestService service = clazz.getAnnotation(TestService.class);
                        String beanName = service.value();
                        //2、默认首字母小写,如果没有,则使用默认的beanName
                        if ("".equals(beanName.trim())) {
                            beanName = toLowerFirstCase(clazz.getSimpleName());
                        }
                        Object instance = clazz.newInstance();
                        ioc.put(beanName, instance);
                        //3、根据类型自动赋值
                        for (Class<?> i : clazz.getInterfaces()) {
                            if (ioc.containsKey(i.getName())) {
                                throw new Exception("The" + i.getName() + "is exists!!");
                            }
                            //把接口的类型当成key
                            ioc.put(i.getName(), instance);
                        }
                    } else {
                        continue;
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        private String toLowerFirstCase(String simpleName) {
            char[] chars = simpleName.toCharArray();
            chars[0] += 32;
            return String.valueOf(chars);
    
        }
    
        private void doAutowired() {
            //判断ioc容器是否为空
            if (ioc.isEmpty()) {
                return;
            }
    
            //获取所有的字段类型,private public protected
            for (Map.Entry<String, Object> entry : ioc.entrySet()) {
                Field[] fields = entry.getValue().getClass().getDeclaredFields();
                for (Field field : fields) {
                    //判断是否包含自动注入字段
                    if (!field.isAnnotationPresent(TestAutowired.class)) {
                        return;
                    }
                    //取得方法名
                    TestAutowired autowired = field.getAnnotation(TestAutowired.class);
                    String beanName = autowired.value().trim();
                    //如果为空则使用接口类型作为key
                    if ("".equals(beanName)) {
                        beanName = field.getType().getName();
                    }
                    //加了@Autowired 但是不是public类型,反射强制访问
                    field.setAccessible(true);
    
                    try {
                        field.set(entry.getValue(), ioc.get(beanName));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
    
                }
            }
    
    
        }
    
        private void doScanner(String scanPackage) {
            //转换文件路径 将 . 替换为 /
            URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
            File classPath = new File(url.getFile());
            for (File file : classPath.listFiles()) {
                if (file.isDirectory()) {
                    doScanner(scanPackage + "." + file.getName());
                } else {
                    if (!file.getName().endsWith(".class")) {
                        continue;
                    }
                    String className = (scanPackage + "." + file.getName().replace(".class", ""));
                    classNames.add(className);
                }
            }
    
        }
    
        private void doLoadConfig(String contextConfigLocation) {
            //根据类路径找到Spring 主配置文件所在的路径
            //读取并将其保存在properties对象中
            InputStream fis = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
            try {
                contextConfig.load(fis);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (null != fis) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    

    3、运行阶段

    调用doGet(),doPost()中的 doDispatch()方法

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws InvocationTargetException, IllegalAccessException {
            //获取url
            String url = req.getRequestURI();
            String contextPath = req.getContextPath();
            //拼接名字
            url = url.replaceAll(contextPath, "").replaceAll("/+", "/");
            if (!this.handlerMapping.containsKey(url)) {
            //这里可以抛出404
                return;
            }
            Method method = this.handlerMapping.get(url);
    
            //第一个参数:方法所在的实例
            //第二个参数:调用时所需要的实参
    
            Map<String, String[]> params = req.getParameterMap();
            //投机取巧方法
            String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
            method.invoke(ioc.get(beanName),new Object[]{req,resp,params.get("name")[0]});
    
    
        }
    
    展开全文
  • 手写spring源码

    2020-07-08 17:44:58
    如今我们使用spring等框架已经手到擒来了,如果说知道用spring的人有100个,但我想会真正的去看框架源码深入探索的就可能只有30个了,如何才能让自己比别人更优秀呢,来吧,就是这里没错。 原文链接 通过我看Tom...

    如今我们使用spring等框架已经手到擒来了,如果说知道用spring的人有100个,但我想会真正的去看框架源码深入探索的就可能只有30个了,如何才能让自己比别人更优秀呢,来吧,就是这里没错。
    原文链接

    通过我看Tom老师的直播来还原一下spring的编写过程吧,希望对那些正在学习spring的有一点点帮助。

    首先来整理一下整个流程。
    大致分为三步:配置,初始化,运行。
    在这里插入图片描述

    一:项目结构

    在这里插入图片描述

    二:在pom.xml中我们就加入(maven)

    在这里插入图片描述
    然后我们需要创建一个GPDispatcherServlet并继承HttpService,重写init(),doPost(),和doGet()方法。
    在web.xml中我们也需要配置一下以下信息:
    在这里插入图片描述
    在application.properties里面就只需要加一个访问路径:
    在这里插入图片描述
    接下来配置注解我们可以自己配也可以直接用spring。@Controller,@Service,@RequestMapping,@Autowired,@RequestParam
    感兴趣去配置玩玩哈。

    三:来声明初始化变量

    在这里插入图片描述
    1.当Servlet容器启动时,会调用GPDispatcherServlet的init()方法,从init方法的参数中,我们可以拿到主配置文件的路径,从能够读取到配置文件中的信息。前面我们已经介绍了Spring的三个阶段,现在来完成初始化阶段的代码。在init()方法中,定义好执行步骤,如下:
    在这里插入图片描述
    2.doLoadConfig()方法的实现,将文件读取到Properties对象中:
    在这里插入图片描述
    3.doScanner()方法,递归扫描出所有的Class文件
    在这里插入图片描述
    4.doInstance()方法,初始化所有相关的类,并放入到IOC容器之中。IOC容器的key默认是类名首字母小写,如果是自己设置类名,则优先使用自定义的。因此,要先写一个针对类名首字母处理的工具方法。
    在这里插入图片描述
    5.然后,再处理相关的类。
    在这里插入图片描述
    6.doAutowired()方法,将初始化到IOC容器中的类,需要赋值的字段进行赋值
    在这里插入图片描述
    7.initHandlerMapping()方法,将GPRequestMapping中配置的信息和Method进行关联,并保存这些关系。
    在这里插入图片描述
    到这里为止,初始化阶段的代码就全部完成啦。

    四:运行阶段

    来到运行阶段,当用户发送请求被Servlet接受时,都会统一调用doPost方法,我先在doPost方法中再调用doDispach()方法,代码如下:
    在这里插入图片描述
    doDispatch()方法是这样写的:
    在这里插入图片描述

    五、效果演示

    到此我们就把spring写完啦。在浏览器输入http://localhost:8080/demo/query.json?name=Tom,就会得到下面的结果:
    在这里插入图片描述
    如果想深入了解Spring,可以关注Tom老师最近出的新书《Spring5核心原理与30个类手写实战》哦。

    展开全文
  • 手写 Spring MVC

    万次阅读 多人点赞 2019-07-20 20:11:00
    手写 Spring 不多说,简历装 X 必备。不过练好还是需要求一定的思维能力。 一、整体思路 思路要熟练背下来 1)配置阶段 配置 web.xml: XDispatchServlet 设定 init-param: contextConfigLocation = classpath:...
  • 手写Spring核心原理

    2020-12-24 14:54:15
       本人从事后端刚满一年,主要从事java和python工作,最近在学习spring源码,为了加深印象,本文将通过代码+图文+文字说明的形式来写一个自定义的spring核心控制器dispatcherServlet以及相关组件,以供后续学习。...
  • 最近学习了一下spring的相关内容,所以也就想要照猫画虎地记录和实现一下spring的框架,mini-spring尽量实现spring的核心功能。 一、项目结构 本项目使用gradle进行构建,其中mini-spring为根模块,包含两个子模块:...
  • 手写Spring系列 手动实现一个Spring框架 内容持续更新,详细教程欢迎关注我的博客 最近学习了一下spring的相关内容,所以也就想要照猫画虎地记录和实现一下spring的框架,通过阅读这些也希望能够消除对Spring框架的...
  • 手写springIoC

    2021-03-19 14:05:44
    手写springIoC
  • 使用反射技术和注解类实现手写SpringIOC,并使用SpringJDBC进行依赖注入测试。
  • 手写spring1.0

    2019-11-15 10:13:41
    手写spring1.0 springmvc 精简版,适合入门学习spring源码基础,适合新手学习 ,spring 基础项目版
  • 手写Spring之集成Tomcat与Servlet一、Web服务模型及servletWeb服务器请求流程![在这里插入图片描述](https://img-blog.csdnimg.cn/20190605130519749.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,...
  • 手写spring资料.zip

    2020-08-04 17:04:00
    用于spring手写基础,采用maven的jetty构建基础环境,与https://editor.csdn.net/md/?articleId=107790361博客对应
  • 手写spring中的IoC和AOP一、核心思想二、手写实现IoC和AOP三、代码仓库 一、核心思想 IoC和AOP不是spring提出来的,在spring之前就已经存在,只不过更偏向理论化,spring在技术层面把这两个思想做了非常好的实现。在...
  • 手写Spring框架 handwritten-mvc-framwork 为自己实现的Spring框架 handwritten-mvc-example 为该框架的实例 数据库表 user.sql 在 handwritten-mvc-exampl 的 resources 目录中. 数据库名可以在 handwritten....
  • 手写Spring AOP实现Demo

    2019-04-27 22:15:59
    1.创建一个配置类MainConfigAOP,需要将此类注入到IOC容器中,就需要在此类上添加注解@Configuration或者是@Component,代码如下: 2.创建一个切面类LogAspect,里面定义方法,分别使用@Before,@After,@After...
  • 手写spring ioc 终版

    2019-12-19 13:56:36
    ImportBeanDefinitionRegistry +MapperScan+FactoryBean笔者也都实现了这些,并且测试用例有此案例,通过此例可以了解mybatis是怎样利用spring的这两个扩展接口来完成mapper的扫描与mapper的动态代理的
  • 最近心血来潮,想自己写一个简单的Spring框架,过程中有啥问题的请各位大佬指出 开发准备:JDK:1.8 开发工具:Idea jar:servlet-api.jar 下面开始; 1.新建一个java项目,项目结构下图: 各文件的代码: ...
  • 手写Spring注解实现Spring AOP切面动态拦截 1.新建注解类命名为PointCutAddress package com.map.common.annotation; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy....
  • 手写SpringIoc的XML实现方式,仿照Spring底层Bean工厂类实现ClassPathXmlApplicationContext
  • 手写spring框架ioc+aop+mvc
  • 必读,代码只是模仿spring的一个大致设计思路,很多细节问题并没有考虑到,代码本身还存在很多的问题,只能供参考一下。 从 Servlet 到 ApplicationContext 我们已经了解 SpringMVC 的入口是 DispatcherSerlvet,...
  • 手写 Spring - 详细思路与实践

    千次阅读 多人点赞 2019-08-13 23:09:53
    手写 Spring - 详细思路与实践 之前的一篇 手写 Spring,这样的文章很多,到处都是,要说真的能简单手写Spring MVC 其实不多,因为要理解,记忆,实践才能掌握,这不是一篇博客就能实现的,可能需要两篇。。再说...
  • 我是这样手写Spring的(教材版)

    千次阅读 2018-09-19 22:24:07
    但深入了解Spring的却寥寥无几,现在,我带大家一起来看看,我是如何手写Spring的。我将结合对Spring十多年的研究经验,用不到400行代码来描述Spring IOC、DI、MVC的精华设计思想,并保证基本功能完整。 首先,我们...
  • 手写springAop框架3.zip

    2021-03-19 13:57:40
    手写springAop框架3.zip

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,177
精华内容 10,870
关键字:

手写spring

spring 订阅