<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          手寫Spring框架之AOP

          共 18865字,需瀏覽 38分鐘

           ·

          2020-08-24 16:45


          簡(jiǎn)介


          前面兩篇博客已經(jīng)實(shí)現(xiàn)了Bean容器, IOC功能和MVC功能, 本篇博客來(lái)實(shí)現(xiàn)AOP功能和事務(wù)管理.?


          定義注解


          (1) 切面注解


          @Target(ElementType.TYPE)
          @Retention(RetentionPolicy.RUNTIME)
          public?@interface?Aspect {
          ????/**
          ?????* 包名
          ?????*/

          ????String?pkg() default?"";

          ????/**
          ?????* 類名
          ?????*/

          ????String?cls() default?"";
          }


          (2) 事務(wù)注解


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


          搭建代理框架


          毫無(wú)疑問(wèn)這個(gè)代理框架是基于動(dòng)態(tài)代理實(shí)現(xiàn)的, 但加了一個(gè)鏈?zhǔn)酱淼墓δ? 目的是為了解決多重代理的問(wèn)題, 也就是目標(biāo)對(duì)象的方法被多次增強(qiáng).


          (1) Proxy接口


          我們自定義了一個(gè)最上層的代理接口, 其中doProxy()執(zhí)行的是鏈?zhǔn)酱? 具體詳情可以看后面的介紹.


          public?interface?Proxy?{

          ????/**
          ?????* 執(zhí)行鏈?zhǔn)酱?br mpa-from-tpl="t">?????* 所謂鏈?zhǔn)酱? 就是說(shuō), 可將多個(gè)代理通過(guò)一條鏈子串起來(lái), 一個(gè)個(gè)地去執(zhí)行, 執(zhí)行順序取決于添加到鏈上的先后順序
          ?????*/

          ????Object doProxy(ProxyChain proxyChain) throws Throwable;
          }


          (2) ProxyChain類


          這是一個(gè)代理鏈類, proxyList 存儲(chǔ)的是代理列表(也就是增強(qiáng)列表), 當(dāng)執(zhí)行doProxyChain() 方法時(shí)會(huì)按照順序執(zhí)行增強(qiáng), 最后再執(zhí)行目標(biāo)方法.


          public?class?ProxyChain?{

          ????private?final?Class targetClass; //目標(biāo)類
          ????private?final?Object targetObject; //目標(biāo)對(duì)象
          ????private?final?Method targetMethod; //目標(biāo)方法
          ????private?final?MethodProxy methodProxy; //方法代理
          ????private?final?Object[] methodParams; //方法參數(shù)

          ????private?List proxyList = new?ArrayList<>(); //代理列表
          ????private?int?proxyIndex = 0; //代理索引

          ????public?ProxyChain(Class targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List 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;
          ????}

          ????/**
          ?????* 遞歸執(zhí)行
          ?????*/

          ????public?Object doProxyChain()?throws?Throwable {
          ????????Object methodResult;
          ????????if?(proxyIndex < proxyList.size()) {
          ????????????//執(zhí)行增強(qiáng)方法
          ????????????methodResult = proxyList.get(proxyIndex++).doProxy(this);
          ????????} else?{
          ????????????//目標(biāo)方法最后執(zhí)行且只執(zhí)行一次
          ????????????methodResult = methodProxy.invokeSuper(targetObject, methodParams);
          ????????}
          ????????return?methodResult;
          ????}
          }


          (3) AspectProxy類


          AspectProxy是一個(gè)切面抽象類, 實(shí)現(xiàn)了Proxy接口, 類中定義了切入點(diǎn)判斷和各種增強(qiáng). 當(dāng)執(zhí)行 doProxy() 方法時(shí), 會(huì)先進(jìn)行切入點(diǎn)判斷, 再執(zhí)行前置增強(qiáng), 代理鏈的下一個(gè)doProxyChain()方法, 后置增強(qiáng)等.


          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;
          ????}

          ????/**
          ?????* 開始增強(qiáng)
          ?????*/

          ????public?void?begin() {
          ????}

          ????/**
          ?????* 切入點(diǎn)判斷
          ?????*/

          ????public?boolean intercept(Method method, Object[] params) throws Throwable {
          ????????return?true;
          ????}

          ????/**
          ?????* 前置增強(qiáng)
          ?????*/

          ????public?void?before(Method method, Object[] params) throws Throwable {
          ????}

          ????/**
          ?????* 后置增強(qiáng)
          ?????*/

          ????public?void?after(Method method, Object[] params) throws Throwable {
          ????}

          ????/**
          ?????* 異常增強(qiáng)
          ?????*/

          ????public?void?error(Method method, Object[] params, Throwable e) {
          ????}

          ????/**
          ?????* 最終增強(qiáng)
          ?????*/

          ????public?void?end() {
          ????}
          }


          (4) ProxyFactory類


          這是一個(gè)代理工廠類, 我們通過(guò)這個(gè)類來(lái)梳理上面的代理邏輯. ?當(dāng)調(diào)用 ProxyFactory.createProxy(final Class targetClass, final List proxyList) 方法來(lái)創(chuàng)建一個(gè)代理對(duì)象后, 每次執(zhí)行代理方法時(shí)都會(huì)調(diào)用 intercept() 方法, 從而創(chuàng)建一個(gè) ProxyChain 對(duì)象, 并調(diào)用該對(duì)象的 doProxyChain() 方法. 調(diào)用doProxyChain()方法時(shí)會(huì)首先遞歸的執(zhí)行增強(qiáng), 最后再執(zhí)行目標(biāo)方法.


          public?class?ProxyFactory?{

          ????/**
          ?????* 輸入一個(gè)目標(biāo)類和一組Proxy接口實(shí)現(xiàn), 輸出一個(gè)代理對(duì)象
          ?????*/

          ????@SuppressWarnings("unchecked")
          ????public?static? T createProxy(final?Class targetClass, final?List proxyList)?{
          ????????return?(T) Enhancer.create(targetClass, new?MethodInterceptor() {
          ????????????/**
          ?????????????* 代理方法, 每次調(diào)用目標(biāo)方法時(shí)都會(huì)先創(chuàng)建一個(gè) ProxyChain 對(duì)象, 然后調(diào)用該對(duì)象的 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 助手類用來(lái)初始化整個(gè)AOP框架, 邏輯如下:

          框架中所有Bean的實(shí)例都是從Bean容器中獲取, 然后再執(zhí)行該實(shí)例的方法, 基于此, 初始化AOP框架實(shí)際上就是用代理對(duì)象覆蓋掉Bean容器中的目標(biāo)對(duì)象, 這樣根據(jù)目標(biāo)類的Class對(duì)象從Bean容器中獲取到的就是代理對(duì)象, 從而達(dá)到了對(duì)目標(biāo)對(duì)象增強(qiáng)的目的.


          public final class?AopHelper?{

          ????private static?final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);

          ????static?{
          ????????try?{
          ????????????//切面類-目標(biāo)類集合的映射
          ????????????Map, Set>> aspectMap = createAspectMap();
          ????????????//目標(biāo)類-切面對(duì)象列表的映射
          ????????????Map, List<Proxy>> targetMap = createTargetMap(aspectMap);
          ????????????//把切面對(duì)象織入到目標(biāo)類中, 創(chuàng)建代理對(duì)象
          ????????????for?(Map.Entry, List<Proxy>> targetEntry : targetMap.entrySet()) {
          ????????????????Class targetClass = targetEntry.getKey();
          ????????????????List<Proxy> proxyList = targetEntry.getValue();
          ????????????????Object?proxy = ProxyFactory.createProxy(targetClass, proxyList);
          ????????????????//覆蓋Bean容器里目標(biāo)類對(duì)應(yīng)的實(shí)例, 下次從Bean容器獲取的就是代理對(duì)象了
          ????????????????BeanHelper.setBean(targetClass, proxy);
          ????????????}
          ????????} catch?(Exception e) {
          ????????????LOGGER.error("aop failure", e);
          ????????}
          ????}

          ????/**
          ?????* 獲取切面類-目標(biāo)類集合的映射
          ?????*/

          ????private static?Map, Set>> createAspectMap() throws Exception {
          ????????Map, Set>> aspectMap = new?HashMap, Set>>();
          ????????addAspectProxy(aspectMap);
          ????????return?aspectMap;
          ????}

          ????/**
          ?????* 獲取普通切面類-目標(biāo)類集合的映射
          ?????*/

          ????private static?void?addAspectProxy(Map, Set>> aspectMap) throws Exception {
          ????????//所有實(shí)現(xiàn)了AspectProxy抽象類的切面
          ????????Set> aspectClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
          ????????for?(Class aspectClass : aspectClassSet) {
          ????????????if?(aspectClass.isAnnotationPresent(Aspect.class)) {
          ????????????????Aspect aspect = aspectClass.getAnnotation(Aspect.class);
          ????????????????//與該切面對(duì)應(yīng)的目標(biāo)類集合
          ????????????????Set> targetClassSet = createTargetClassSet(aspect);
          ????????????????aspectMap.put(aspectClass, targetClassSet);
          ????????????}
          ????????}
          ????}

          ????/**
          ?????* 根據(jù)@Aspect定義的包名和類名去獲取對(duì)應(yīng)的目標(biāo)類集合
          ?????*/

          ????private static?Set> createTargetClassSet(Aspect aspect) throws Exception {
          ????????Set> targetClassSet = new?HashSet>();
          ????????// 包名
          ????????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;
          ????}

          ????/**
          ?????* 將切面類-目標(biāo)類集合的映射關(guān)系 轉(zhuǎn)化為 目標(biāo)類-切面對(duì)象列表的映射關(guān)系
          ?????*/

          ????private static?Map, List<Proxy>> createTargetMap(Map, Set>> aspectMap) throws Exception {
          ????????Map, List<Proxy>> targetMap = new?HashMap, List<Proxy>>();
          ????????for?(Map.Entry, Set>> proxyEntry : aspectMap.entrySet()) {
          ????????????//切面類
          ????????????Class aspectClass = proxyEntry.getKey();
          ????????????//目標(biāo)類集合
          ????????????Set> targetClassSet = proxyEntry.getValue();
          ????????????//創(chuàng)建目標(biāo)類-切面對(duì)象列表的映射關(guān)系
          ????????????for?(Class targetClass : targetClassSet) {
          ????????????????//切面對(duì)象
          ????????????????Proxy?aspect = (Proxy) aspectClass.newInstance();
          ????????????????if?(targetMap.containsKey(targetClass)) {
          ????????????????????targetMap.get(targetClass).add(aspect);
          ????????????????} else?{
          ????????????????????//切面對(duì)象列表
          ????????????????????List<Proxy> aspectList = new?ArrayList<Proxy>();
          ????????????????????aspectList.add(aspect);
          ????????????????????targetMap.put(targetClass, aspectList);
          ????????????????}
          ????????????}
          ????????}
          ????????return?targetMap;
          ????}
          }


          (6) HelperLoader 類


          在手寫Spring之MVC這篇博客里我們定義了這個(gè)類, 目的是為了集中加載 ClassHelper, BeanHelper, IocHelper, ControllerHelper 這四個(gè)助手類, 這里還要再加上個(gè) 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實(shí)例


          我們創(chuàng)建一個(gè)監(jiān)控接口性能的切面, 當(dāng)接口被調(diào)用后, 打印接口的執(zhí)行時(shí)間.


          (1) 業(yè)務(wù)類


          public?interface?IUserService?{
          ????List getAllUser();
          }

          @Service
          public?class?UserService?implements?IUserService?{
          ????/**
          ?????* 獲取所有用戶
          ?????*/

          ????public?List getAllUser() {
          ????????List 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 userList = userService.getAllUser();
          ????????return?new?View("index.jsp").addModel("userList", userList);
          ????}
          }


          (3) 接口性能監(jiān)控切面


          目標(biāo)類是 com.tyshawn.controller 包下的 UserController, 切入點(diǎn)是 getUserList() 方法. 日志記錄切入點(diǎn)方法的執(zhí)行時(shí)間.


          @Aspect(pkg = "com.tyshawn.controller", cls = "UserController")
          public?class?EfficientAspect?extends?AspectProxy?{
          ????private?static?final?Logger LOGGER = LoggerFactory.getLogger(EfficientAspect.class);

          ????private?long?begin;

          ????/**
          ?????* 切入點(diǎn)判斷
          ?????*/

          ????@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) 結(jié)果


          http://localhost:8081/handwritten/userList

          ---------- begin ----------
          time: 1001ms
          ----------- end -----------


          事務(wù)管理


          我們要達(dá)到的目的是, 當(dāng)我們?cè)谀繕?biāo)方法上加 @Transactional 注解后, 該方法就擁有了事務(wù)管理. 用AOP實(shí)現(xiàn)的思路就是, 前置增強(qiáng)為開啟事務(wù), 后置增強(qiáng)為提交事務(wù), 異常增強(qiáng)為回滾事務(wù).


          (1) DatabaseHelper 助手類


          DatabaseHelper 為數(shù)據(jù)庫(kù)操作助手類, 可以通過(guò)該助手類進(jìn)行增刪改查, 事務(wù)等一系列的數(shù)據(jù)庫(kù)操作.


          public?final class?DatabaseHelper?{

          ????private?static?final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelper.class);

          ????private?static?final ThreadLocal CONNECTION_HOLDER;

          ????private?static?final QueryRunner QUERY_RUNNER;

          ????private?static?final BasicDataSource DATA_SOURCE;

          ????static?{
          ????????CONNECTION_HOLDER = new?ThreadLocal();

          ????????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());
          ????}

          ????/**
          ?????* 獲取數(shù)據(jù)源
          ?????*/

          ????public?static?DataSource getDataSource() {
          ????????return?DATA_SOURCE;
          ????}

          ????/**
          ?????* 獲取數(shù)據(jù)庫(kù)連接
          ?????*/

          ????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;
          ????}

          ????/**
          ?????* 開啟事務(wù)
          ?????*/

          ????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);
          ????????????}
          ????????}
          ????}

          ????/**
          ?????* 提交事務(wù)
          ?????*/

          ????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();
          ????????????}
          ????????}
          ????}

          ????/**
          ?????* 回滾事務(wù)
          ?????*/

          ????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();
          ????????????}
          ????????}
          ????}

          ????/**
          ?????* 查詢實(shí)體
          ?????*/

          ????public?static? T queryEntity(Class entityClass, String sql, Object... params) {
          ????????T entity;
          ????????try?{
          ????????????Connection conn = getConnection();
          ????????????entity = QUERY_RUNNER.query(conn, sql, new?BeanHandler(entityClass), params);
          ????????} catch?(SQLException e) {
          ????????????LOGGER.error("query entity failure", e);
          ????????????throw?new?RuntimeException(e);
          ????????}
          ????????return?entity;
          ????}

          ????/**
          ?????* 查詢實(shí)體列表
          ?????*/

          ????public?static? List queryEntityList(Class entityClass, String sql, Object... params) {
          ????????List entityList;
          ????????try?{
          ????????????Connection conn = getConnection();
          ????????????entityList = QUERY_RUNNER.query(conn, sql, new?BeanListHandler(entityClass), params);
          ????????} catch?(SQLException e) {
          ????????????LOGGER.error("query entity list failure", e);
          ????????????throw?new?RuntimeException(e);
          ????????}
          ????????return?entityList;
          ????}

          ????/**
          ?????* 執(zhí)行更新語(yǔ)句(包括: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;
          ????}

          ????/**
          ?????* 插入實(shí)體
          ?????*/

          ????public?static? boolean insertEntity(Class entityClass, Map 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;
          ????}

          ????/**
          ?????* 更新實(shí)體
          ?????*/

          ????public?static? boolean updateEntity(Class entityClass, long?id, Map 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 paramList = new?ArrayList();
          ????????paramList.addAll(fieldMap.values());
          ????????paramList.add(id);
          ????????Object[] params?= paramList.toArray();

          ????????return?update(sql, params) == 1;
          ????}

          ????/**
          ?????* 刪除實(shí)體
          ?????*/

          ????public?static? boolean deleteEntity(Class entityClass, long?id) {
          ????????String sql = "DELETE FROM "?+ entityClass.getSimpleName() + " WHERE id = ?";
          ????????return?update(sql, id) == 1;
          ????}
          }


          (2) TransactionProxy 類


          TransactionProxy 為事務(wù)切面類, 同樣實(shí)現(xiàn)了Proxy接口, 其 doProxy() 方法就是先判斷代理方法上有沒有 @Transactional 注解, 如果有就加上事務(wù)管理, 沒有就直接執(zhí)行.


          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注解的方法要做事務(wù)處理
          ????????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部分我們已經(jīng)知道了 AopHelper 的作用以及實(shí)現(xiàn)邏輯, 事務(wù)代理相比普通代理的差別是, 我們默認(rèn)所有Service對(duì)象都被代理了, 也就是說(shuō)通過(guò)Service的Class對(duì)象, 從Bean容器中得到的都是代理對(duì)象, 我們?cè)趫?zhí)行代理方法時(shí)會(huì)判斷目標(biāo)方法上是否存在 @Transactional 注解, 有就加上事務(wù)管理, 沒有就直接執(zhí)行, 如上面的代碼?


          public?interface?IUserService?{
          ????List getAllUser();

          ????User GetUserInfoById(Integer id);

          ????boolean?updateUser(int?id, Map fieldMap);
          }

          @Service
          public?class?UserService?implements?IUserService?{
          ????/**
          ?????* 獲取所有用戶
          ?????*/

          ????public?List getAllUser()?{
          ????????String sql = "SELECT * FROM user";
          ????????return?DatabaseHelper.queryEntityList(User.class, sql);
          ????}

          ????/**
          ?????* 根據(jù)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 fieldMap)?{
          ????????return?DatabaseHelper.updateEntity(User.class, id, fieldMap);
          ????}
          }


          事務(wù)管理實(shí)例


          (1) 業(yè)務(wù)類


          public?interface?IUserService?{
          ????List getAllUser();

          ????User GetUserInfoById(Integer id);

          ????boolean?updateUser(int?id, Map fieldMap);
          }

          @Service
          public?class?UserService?implements?IUserService?{
          ????/**
          ?????* 獲取所有用戶
          ?????*/

          ????public?List getAllUser()?{
          ????????String sql = "SELECT * FROM user";
          ????????return?DatabaseHelper.queryEntityList(User.class, sql);
          ????}

          ????/**
          ?????* 根據(jù)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 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 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頁(yè)面


          <%@?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>用戶idth>
          ????????<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) 結(jié)果


          http://localhost:8081/handwritten/userList


          用戶信息



          點(diǎn)擊編輯, 控制臺(tái)打印: 
          begin?transaction
          commit?transaction


          結(jié)束


          到此為止, handwritten-mvc-framwork 框架的所有功能都已實(shí)現(xiàn), 包括Bean容器, IOC, MVC, AOP, 事務(wù)管理, 大家可以多看看源代碼, 思路理順之后一定會(huì)收獲良多.


          原文鏈接:csdn.net/litianxiang_kaola/article/details/86647057



          瀏覽 51
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    亚洲综合影院 | 色婷婷天堂网 | 亚洲色图欧美色图自慰直播 | 黄色视频在线免费观看高清视频 | 大香蕉最新视频网站 |