Spring

1. 手动编写注解事务
1.1 思路

思路

1.2
//编程事务(需要手动begin 手动回滚  手都提交)
@Component()
@Scope("prototype") // 设置成原型解决线程安全
public class TransactionUtils {

	private TransactionStatus transactionStatus;
	// 获取事务源
	@Autowired
	private DataSourceTransactionManager dataSourceTransactionManager;

	// 开启事务
	public TransactionStatus begin() {
		transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
		return transactionStatus;
	}

	// 提交事务
	public void commit(TransactionStatus transaction) {
		dataSourceTransactionManager.commit(transaction);
	}

	// 回滚事务
	public void rollback() {
		System.out.println("rollback");
		dataSourceTransactionManager.rollback(transactionStatus);
	}

}

注解类

@Autowired
	private TransactionUtils transactionUtils;

	@AfterThrowing("execution(* com.itmayiedu.service.*.*.*(..))")
	public void afterThrowing() throws NoSuchMethodException, SecurityException {
		// isRollback(proceedingJoinPoint);
		System.out.println("程序发生异常");
		// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		// TransactionStatus currentTransactionStatus =
		// TransactionAspectSupport.currentTransactionStatus();
		// System.out.println("currentTransactionStatus:" +
		// currentTransactionStatus);
		transactionUtils.rollback();
	}

	// // 环绕通知 在方法之前和之后处理事情
	@Around("execution(* com.itmayiedu.service.*.*.*(..))")
	public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

		// 调用方法之前执行
		TransactionStatus transactionStatus = begin(proceedingJoinPoint);
		proceedingJoinPoint.proceed();// 代理调用方法 注意点: 如果调用方法抛出异常不会执行后面代码
		// 调用方法之后执行
		commit(transactionStatus);
	}

	public TransactionStatus begin(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {

		// // 判断是否有自定义事务注解
		ExtTransaction declaredAnnotation = getExtTransaction(pjp);
		if (declaredAnnotation == null) {
			return null;
		}
		// 如果有自定义事务注解,开启事务
		System.out.println("开启事务");
		TransactionStatus transactionStatu = transactionUtils.begin();
		return transactionStatu;
	}

	public void commit(TransactionStatus transactionStatu) {
		if (transactionStatu != null) {
			// 提交事务
			System.out.println("提交事务");
			transactionUtils.commit(transactionStatu);
		}
	}

	public ExtTransaction getExtTransaction(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
		// 获取方法名称
		String methodName = pjp.getSignature().getName();
		// 获取目标对象
		Class<?> classTarget = pjp.getTarget().getClass();
		// 获取目标对象类型
		Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
		// 获取目标对象方法
		Method objMethod = classTarget.getMethod(methodName, par);
		// // 判断是否有自定义事务注解
		ExtTransaction declaredAnnotation = objMethod.getDeclaredAnnotation(ExtTransaction.class);
		if (declaredAnnotation == null) {
			System.out.println("您的方法上,没有加入注解!");
			return null;
		}
		return declaredAnnotation;

	}

	// 回滚事务
	public void isRollback(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
		// // 判断是否有自定义事务注解
		ExtTransaction declaredAnnotation = getExtTransaction(pjp);
		if (declaredAnnotation != null) {
			System.out.println("已经开始回滚事务");
			// 获取当前事务 直接回滚
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return;
		}
	}

使用自定义注解

@ExtTransaction
public void add() {
userDao.add("test001", 20);
int i = 1 / 0;
System.out.println("################");
userDao.add("test002", 21);
}
2. 手写springmvc
2.1 SpringMVC的运行流程

springmvc执行流程
⑴ 用户发送请求至前端控制器DispatcherServlet

⑵ DispatcherServlet收到请求调用HandlerMapping处理器映射器。

⑶ 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

⑷ DispatcherServlet通过HandlerAdapter处理器适配器调用处理器

⑸ 执行处理器(Controller,也叫后端控制器)。

⑹ Controller执行完成返回ModelAndView

⑺ HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet

⑻ DispatcherServlet将ModelAndView传给ViewReslover视图解析器

⑼ ViewReslover解析后返回具体View

⑽ DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。

⑾ DispatcherServlet响应用户。

2.2 Servlet 生命周期

Servlet 加载—>实例化—>服务—>销毁。
init():
在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。
service():
它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
destroy():
仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。

1.3 手写SpringMVC思路

1.web.xml加载
 为了读取web.xml中的配置,我们用到ServletConfig这个类,它代表当前Servlet在web.xml中的配置信息。通过web.xml中加载我们自己写的MyDispatcherServlet和读取配置文件。
2、初始化阶段
  在前面我们提到DispatcherServlet的initStrategies方法会初始化9大组件,但是这里将实现一些SpringMVC的最基本的组件而不是全部,按顺序包括:
加载配置文件
扫描用户配置包下面所有的类
拿到扫描到的类,通过反射机制,实例化。并且放到ioc容器中(Map的键值对 beanName-bean) beanName默认是首字母小写
初始化HandlerMapping,这里其实就是把url和method对应起来放在一个k-v的Map中,在运行阶段取出
3、运行阶段
  每一次请求将会调用doGet或doPost方法,所以统一运行阶段都放在doDispatch方法里处理,它会根据url请求去HandlerMapping中匹配到对应的Method,然后利用反射机制调用Controller中的url对应的方法,并得到结果返回。按顺序包括以下功能:
异常的拦截
获取请求传入的参数并处理参数
通过初始化好的handlerMapping中拿出url对应的方法名,反射调用

/**
 * @DESC: 自定义DispatchServlet
 * ### 1.创建一个前端控制器 ExtDispatcherServlet 拦截所有请求(springMvc 基于servlet实现)<br/>
 * ### 2.出啊实话操作重写servlet init方法<br/>
 * ###### 2.1 将扫包范围所有的类,注入到SpringMvc容器里,存放在Map集合中key为默认名小写,value对象<br/>
 * ###### 2.2 将url映射和方法进行关联
 * ########## 2.2.1 判断类上是否有注解,使用java反射机制循环遍历方法,判断方法上是否存在注解,进行封装url和方法对应存入集合中
 * ### 3. 处理请求 重写get或post方法
 * ###### 3.1 获取请求url,从urlBeans集合获取实例对象,获取成功实例对象后,调用urlMethods集合获取方法名称,使用反射执行
 * @author: zhouben
 * @date: 2019/10/31 0031 10:23
 */
public class ExtDispatchServlet extends HttpServlet {

    // springmvc 容器对象 key:类名id ,value 对象
    private ConcurrentHashMap<String, Object> beans = new ConcurrentHashMap<>();
    // springmvc 容器对象 keya:请求地址 ,vlue类
    private ConcurrentHashMap<String, Object> urlBeans = new ConcurrentHashMap<>();
    // springmvc 容器对象 key:请求地址 ,value 方法名称
    private ConcurrentHashMap<String, String> methodBeans = new ConcurrentHashMap<>();

    @Override
    public void init() throws ServletException {
        //1.将扫包范围所有的类,注入到SpringMvc容器里,存放在Map集合中key为默认名小写,value对象
        List<Class<?>> classes = ClassUtil.getClasses("com.zben.design.controller");

        try {
            findClassMVCAnnotation(classes);
            //映射方法进行关联
            handlerMapping();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // #################处理请求####################
        //1.获取请求路径
        String requestURI = req.getRequestURI();
        //2.从Map集合中获取控制对象
        Object obj = urlBeans.get(requestURI);
        if (obj == null) {
            resp.getWriter().print("not found 404  url");
            return;
        }
        //3.使用url获取方法
        String methodName = methodBeans.get(requestURI);
        if (StringUtils.isEmpty(methodName)) {
            resp.getWriter().print("not found method");
            return;
        }
        //4. 通过反射机制调用方法
        String resultPage = (String) invoke(obj, methodName);
        //5. 调用视图解析器转发
        extViewResovler(resultPage, req, resp);

    }

    private void extViewResovler(String pageName, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String prefix = "/";
        String suffix = ".jsp";
        request.getRequestDispatcher(prefix + pageName +suffix).forward(request, response);
    }

    private Object invoke(Object obj, String methodName) {
        Class<?> clazz = obj.getClass();
        try {
            Method method = clazz.getDeclaredMethod(methodName);
            Object result = method.invoke(obj);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //将url映射和方法进行关联
    private void handlerMapping() {
        if (!beans.isEmpty()) {
            for (Map.Entry<String, Object> entity : beans.entrySet()) {
                Object value = entity.getValue();
                Class<?> classes = value.getClass();
                //判断类上是否有注解
                ExtRequestMapping extRequestMapping = value.getClass().getDeclaredAnnotation(ExtRequestMapping.class);
                String baseUrl = "";
                if (extRequestMapping != null) {
                    //获取注解上的url
                    baseUrl = extRequestMapping.value();
                }
                //判断方法上是否有加url映射地址
                Method[] declaredMethods = classes.getDeclaredMethods();
                for (Method method : declaredMethods) {
                    //获取方法上是否有注解
                    ExtRequestMapping annotation = method.getDeclaredAnnotation(ExtRequestMapping.class);
                    if (annotation != null) {
                        String url = baseUrl + annotation.value();
                        // springmvc 容器对象 keya:请求地址 ,value类
                        urlBeans.put(url, value);
                        // springmvc 容器对象 key:请求地址 ,value 方法名称
                        methodBeans.put(url, method.getName());
                    }
                }
            }
        }
    }

    //注入到SpringMvc容器里
    private void findClassMVCAnnotation(List<Class<?>> classes) throws InstantiationException, IllegalAccessException, ClassNotFoundException {

        for (Class<?> classInfo : classes) {
            ExtController extController = classInfo.getDeclaredAnnotation(ExtController.class);
            //判断类上是否有次注解
            if (extController != null) {
                //注入到springmvc容器中
                //转换成类名第一个字母小写
                String beanId = ClassUtil.toLowerCaseFirstOne(classInfo.getSimpleName());
                beans.put(beanId, ClassUtil.newInstance(classInfo));
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值