一个自定义的IOC,AOP,MVC,简化版Mybatis框架

16 篇文章 2 订阅
1 篇文章 0 订阅

使用反射,cglib,注解结合,实现一个最简单的IOC, 最简单AOP,最简单的MVC(目前只支持restful JSON格式的数据响应), jdbc数据访问封装框架,当然这个框架非常不稳定、不成熟的自我学习、娱乐的框架

像ioc,aop,mybatis,mvc这样的概念就不在阐述了, 我所理解的也不一定正确。

项目结构图:

这里写图片描述

IOC实现-注解定义

@Component: 组件注解,该注解标注在类上,表示这个类的实例创建将交由框架维护

@Autowired:属性注入,标注该注解的属性在类实例化的时候会自动进行属性注入,无需手动set或者是赋值

@Value: 配置属性注入,使用这个注解可以注入profile中定义的属性,但是在使用这个注解前,必须先加载系统profile

IOC实现-代码实现

由于代码量较多原因,本文不贴代码,文章最后会提供git连接

ConfigUtil:类中定义读取系统配置文件代码,将配置文件中属性名和值保存到一个map中

ReflectionUtil:这个工具类中采用反射的方式实现类实例化,方法调用,属性设置三个工具方法

ClassUtil:类加载的工具类,包含获取类加载器,获取指定包下的所有类等工具方法

ClassManager:类管理工具,包含获取标注有指定注解的类集合,获取指定类上的指定注解,判断一个类是否代理(AOP)

BeanManager:实例管理类,包含框架初始化时候生成类实例,对类进行属性注入设置两个大功能,这个类中需要注意的是可能出现属性嵌套注入的情况,该类实例是否单例等

实现以上这些, 最基本的IOC框架就算实现了

AOP实现-注解

AOP的实现相对ioc而言,难了很多,要考虑前置代理, 后置代理,环绕代理,异常代理,如果判断一个方法是否需要做这些代理,还要考虑参数传递,不写代码不知道, 下手的时候发现,到处都是坑,到目前为止,在这个框架中也只是实现了前置代理,后续再拓展其他功能吧

@Aspect 标准有该注解的类表示切面类,及这里边定义的方法为切面方法

@Before,@After,这个注解的内容有点复杂,包含类切面方向(前置,后置,环绕,异常),连接点等信息,value表示需要被代理的方法,modifier表示方法声明,returnType表示返回类型,args参数类型,其中需要注意的是returnType 默认After.class表示匹配所有,args默认Before.class表示匹配所有,vaule中(..)表示多级,(*)表示任意字符样例:(..*com.mjlf..*.ProxyFunction)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {
    String value();
    String modifier() default "public";
    Class<?> returnType() default After.class;
    Class<?>[] args() default {Before.class};
}
AOP实现-实现类介绍

AdviseUtil:这个类中主要定义了判断一个方法是否需要被代理的方法

AdviseMethod:切面方法,需要要被代理的方法的属性,方法上定义的注解(@Before),被代理方法本身,被代理方法所在类实例,方法参数类型,方法参数名称,方法返回值类型,返回值名称(还没实现)

AdviseMethodManager:这个类主要是用在框架初始化的时候统计需要切面信息,及标注有@Aspect的类中标注有@Before等方法

ProxyManager:使用cglib方法生成类对象,需要注意的是, 后边实现的jdbc封装也使用到了cglib,所以这个类不单单是生成AOP所以代理的类的实例

JDBC封装-注解

对jdbc封装,采用的方式有点类似mybatis,

@Mapper:标注在类上,表示这个类中包含于数据库交互的方法

@Param:标注在参数上,表示需要传递给sql语句的字段属性,例:@param(“id”) int id

@Sql:标注在方法上,表示这个方法需要需要与数据库交互,执行sql语句为@Sql注解中的value属性

sql写法样例:SELECT a, b FROM table_tbl WHERE id = #{id}

@Mapper
public class UserDao {

    @Sql("SELECT user_name AS username, password FROM t_user WHERE user_name = #{username}")
    public List<User> getUserByName(@Param("username") String username){
        return null;
    }
}
JDBC封装-类介绍

ConnectionManager:管理连接,采用队列实现,初始化的时候创建指定连接数量,这里需要优化

MapperProxy:主要负责生成标注有@Mapper类实例,这个类是最复杂的,包含sql格式转换,参数绑定,结果封装等

MVC 封装-注解

首次使用servlet3.0实现网络模块

@Controller 控制器注解

@RequestMapping 注解映射请求路径

MVC封装-实现

DispatcherServlet,这个类是这个框架的核心,所有初始化工作都在这个类中进行启动,然后在service中进行请求转发

//初始化
@Override
public void init(ServletConfig config) throws ServletException {
    try {
        BeanManager.init();
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        throw new ServletException("连接失败");
    }
    RequestManager.init();
}

//请求转发
@Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {

            ReqParams reqParams = new ReqParams();
            Enumeration<String> paramKeys = req.getParameterNames();
            while (paramKeys.hasMoreElements()) {
                String key = paramKeys.nextElement();
                reqParams.addParam(key, req.getParameter(key));
            }

            //获取body中的参数
            BufferedReader br = req.getReader();
            parseParams(br, reqParams);

            String reqPath = req.getPathInfo();
            String reqMethod = req.getMethod().toUpperCase();
            RequestMethod requestMethod = RequestManager.getReqMethod(reqMethod, reqPath);

            if (requestMethod != null) {
                Method method = requestMethod.getReqMethod();
                Object object = requestMethod.getReqObj();
                ReflectionUtil.invokeMethod(object, method, req, resp, reqParams);
            } else {
                resp.sendError(404, "对应的请求处理:" + reqPath);
            }
        } catch (Exception e) {
            logger.error("请求处理过程中出现错误:" + e);
            resp.sendError(500, e.getMessage());
        }
    }

式样样例:

这里写图片描述

Controller:

package com.mjlf.project.web.unlogin;

@Controller
@RequestMapping("/mjlf")
public class LoginController {
    Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private LoginService loginService;

    @RequestMapping(value = "/login", method = "POST")
    public void login(HttpServletRequest request, HttpServletResponse response, ReqParams params) throws IOException {
        JSONObject jsonObject = null;

        String username = params.getParam("username");
        String password = params.getParam("password");

        User user = new User();
        user.setPassword(password);
        user.setUsername(username);

        if(loginService.login(user)){
            jsonObject = new JSONObject();
            jsonObject.put("loginStatus", "yes");
        }else {
            jsonObject = new JSONObject();
            jsonObject.put("loginStatus", "no");
        }

        response.getWriter().write(jsonObject.toString());
    }
}

Service:

package com.mjlf.project.service;

/**
 * 登录服务类
 */
@Component
public class LoginService {

    @Autowired
    private UserDao userDao;

    public boolean login(User user){
        List<User> users = userDao.getUserByName(user.getUsername());
        for(User u : users){
            if(user.getUsername().equals(u.getUsername()) && user.getPassword().equals(u.getPassword())){
                return true;
            }
        }
        return false;
    }

    public UserDao getUserDao(){
        return this.userDao;
    }
}

DAO:

@Mapper
public class UserDao {

    @Sql("SELECT user_name AS username, password FROM t_user WHERE user_name = #{username}")
    public List<User> getUserByName(@Param("username") String username){
        return null;
    }
}

Aspect:

@Aspect
public class ProjectAspectJ {
    @Before(value = "com.mjlf..LoginService.login", returnType = boolean.class)
    public void showTime(Method method, User user){
        System.out.println(method.getName());
        System.out.println(user);
        System.out.println(new Date());
    }

    public void end(){
        System.out.println("end");
    }
}

结果:可以看到请求之后正常访问都了数据库,而且执行了切面增强方法。

这里写图片描述

这里写图片描述

源码地址:https://gitee.com/mjlfto/mjlf_framework.git

实现过程中参考了:架构探险 从零开始写javaweb框架
链接:https://pan.baidu.com/s/1pa-uuaTgi_8WdP3P93zvlA 密码:dvpk

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值