自定义@Service、@Autowired、@Transact

2020-10-10  本文已影响0人  语隔秋烟_

自定义@Service、@Autowired、@Transactional注解类,完成基于注解的IOC容器(Bean对象创建及依赖注入维护)和声明式事务控制
一、自定义注解

  1. 自定义@Service注解
package com.learn.transfer.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 标注Service
 * @author lijun
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyService {
    public String value() default "";
}
  1. 自定义Autowired
package com.learn.transfer.annotation;

import java.lang.annotation.*;

/**
 * 自动注入
 * @author lijun
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {


    boolean value() default true;
}

  1. 自定义Transactional
package com.learn.transfer.annotation;

import java.lang.annotation.*;

/**
 * @author SCKJ-003
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyTransactional {
    String value() default "TransactionManager";
}

二、接下来,我们看一下controller层、service层、dao层 代码

package com.learn.transfer.servlet;


import com.learn.transfer.annotation.MyAutowired;
import com.learn.transfer.entity.Result;
import com.learn.transfer.factory.BeanFactory;
import com.learn.transfer.service.TransferService;
import com.learn.transfer.utils.JsonUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author lijun
 */
@WebServlet(name="transferServlet",urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {

    private TransferService transferService = (TransferService) BeanFactory.getBean("transferService") ;

    @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 {

        // 设置请求体的字符编码
        req.setCharacterEncoding("UTF-8");

        String fromCardNo = req.getParameter("fromCardNo");
        String toCardNo = req.getParameter("toCardNo");
        String moneyStr = req.getParameter("money");
        int money = Integer.parseInt(moneyStr);

        Result result = new Result();

        try {

            // 2. 调用service层方法
            transferService.transfer(fromCardNo,toCardNo,money);
            result.setStatus("200");
        } catch (Exception e) {
            e.printStackTrace();
            result.setStatus("201");
            result.setMessage(e.toString());
        }

        // 响应
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().print(JsonUtils.object2Json(result));
    }
}

package com.learn.transfer.service;

/**
 * @author 应癫
 */
public interface TransferService {

    void transfer(String fromCardNo,String toCardNo,int money) throws Exception;
}

package com.learn.transfer.service.impl;


import com.learn.transfer.annotation.MyAutowired;
import com.learn.transfer.annotation.MyService;
import com.learn.transfer.annotation.MyTransactional;
import com.learn.transfer.dao.AccountDao;
import com.learn.transfer.entity.Account;
import com.learn.transfer.service.TransferService;

/**
 * @author lijun
 */
@MyService("transferService")
@MyTransactional
public class TransferServiceImpl implements TransferService {

    /**
     * 最佳状态
     *
     * @Description: 最佳状态
     * @Param:
     * @Return:
     * @Author: lijun
     * @Date: 2020/9/11
     **/
    @MyAutowired
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }


    @Override
    public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {

        try{
            Account from = accountDao.queryAccountByCardNo(fromCardNo);
            Account to = accountDao.queryAccountByCardNo(toCardNo);

            from.setMoney(from.getMoney()-money);
            to.setMoney(to.getMoney()+money);
            accountDao.updateAccountByCardNo(to);

            //测试事务回滚
            int c = 1/0;
            accountDao.updateAccountByCardNo(from);

        }catch (Exception e) {
            e.printStackTrace();
            // 抛出异常便于上层servlet捕获
            throw e;
        }

    }
}

package com.learn.transfer.dao;


import com.learn.transfer.entity.Account;

/**
 * @author lijun
 */
public interface AccountDao {

    Account queryAccountByCardNo(String cardNo) throws Exception;

    int updateAccountByCardNo(Account account) throws Exception;

    void text();
}

package com.learn.transfer.dao.impl;


import com.learn.transfer.annotation.MyAutowired;
import com.learn.transfer.annotation.MyService;
import com.learn.transfer.dao.AccountDao;
import com.learn.transfer.entity.Account;
import com.learn.transfer.utils.ConnectionUtils;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * @author lijun
 */
@MyService("AccountDao")
public class AccountDaoImpl implements AccountDao {

    @MyAutowired
    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
        this.connectionUtils = connectionUtils;
    }

    @Override
    public Account queryAccountByCardNo(String cardNo) throws Exception {
        //从连接池获取连接
        // Connection con = DruidUtils.getInstance().getConnection();
        Connection con = connectionUtils.getCurrentThreadConn();
        String sql = "select * from t_account where cardNo=?";
        PreparedStatement preparedStatement = con.prepareStatement(sql);
        preparedStatement.setString(1,cardNo);
        ResultSet resultSet = preparedStatement.executeQuery();

        Account account = new Account();
        while(resultSet.next()) {
            account.setCardNo(resultSet.getString("cardNo"));
            account.setName(resultSet.getString("name"));
            account.setMoney(resultSet.getInt("money"));
        }

        resultSet.close();
        preparedStatement.close();
        //con.close();

        return account;
    }

    @Override
    public int updateAccountByCardNo(Account account) throws Exception {

        // 从连接池获取连接
        // 改造为:从当前线程当中获取绑定的connection连接
        //Connection con = DruidUtils.getInstance().getConnection();
        Connection con = connectionUtils.getCurrentThreadConn();
        String sql = "update t_account set money=? where cardNo=?";
        PreparedStatement preparedStatement = con.prepareStatement(sql);
        preparedStatement.setInt(1,account.getMoney());
        preparedStatement.setString(2,account.getCardNo());
        int i = preparedStatement.executeUpdate();

        preparedStatement.close();
        //con.close();
        return i;
    }

    @Override
    public void text() {
        System.out.println(123);
    }
}

package com.learn.transfer.utils;

import com.learn.transfer.annotation.MyService;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * @author lijun
 */
@MyService
public class ConnectionUtils {


    /**
     * 存储当前线程的连接
     *
     * @Description: TODO
     * @Param:
     * @Return:
     * @Author: lijun
     * @Date: 2020/9/11
     **/
    private ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    /**
     * 从当前线程获取连接
     */
    public Connection getCurrentThreadConn() throws SQLException {
        /**
         * 判断当前线程中是否已经绑定连接,如果没有绑定,需要从连接池获取一个连接绑定到当前线程
          */
        Connection connection = threadLocal.get();
        if(connection == null) {
            // 从连接池拿连接并绑定到线程
            connection = DruidUtils.getInstance().getConnection();
            // 绑定到当前线程
            threadLocal.set(connection);
        }
        return connection;

    }
}



package com.learn.transfer.utils;

import com.alibaba.druid.pool.DruidDataSource;

/**
 * @author lijun
 */
public class DruidUtils {

    private DruidUtils(){
    }

    private static DruidDataSource druidDataSource = new DruidDataSource();


    static {
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setDbType("com.alibaba.druid.pool.DruidDataSource");
        druidDataSource.setUrl("jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxxx?useUnicode=true&characterEncoding=utf8&useSSL=true");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
    }

    public static DruidDataSource getInstance() {
        return druidDataSource;
    }

}


package com.learn.transfer.utils;

import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * JSON工具类(使用的是jackson实现的)
 * @author lijun
 */
public class JsonUtils {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     * @param data
     * @return
     */
    public static String object2Json(Object data) {
        try {
            String string = MAPPER.writeValueAsString(data);
            return string;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将json结果集转化为对象
     * 
     * @param jsonData json数据
     * @param beanType 对象中的object类型
     * @return
     */
    public static <T> T json2Pojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将json数据转换成pojo对象list
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T>List<T> json2List(String jsonData, Class<T> beanType) {
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
        try {
            List<T> list = MAPPER.readValue(jsonData, javaType);
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
}

package com.learn.transfer.utils;

import com.learn.transfer.annotation.MyAutowired;
import com.learn.transfer.annotation.MyService;

import java.sql.SQLException;

/**
 * @author lijun
 *
 * 事务管理器类:负责手动事务的开启、提交、回滚
 */
@MyService
public class TransactionManager {

    @MyAutowired
    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
        this.connectionUtils = connectionUtils;
    }

    /*private TransactionManager(){

    }

    private static TransactionManager transactionManager = new TransactionManager();

    public static TransactionManager getInstance() {
        return  transactionManager;
    }*/



    /**
     * 开启手动事务控制
     *
     * @Description: TODO
     * @Param: []
     * @Return: void
     * @Author: lijun
     * @Date: 2020/9/21
     **/
    public void beginTransaction() throws SQLException {
        connectionUtils.getCurrentThreadConn().setAutoCommit(false);
    }


    // 提交事务
    public void commit() throws SQLException {
        connectionUtils.getCurrentThreadConn().commit();
    }


    // 回滚事务
    public void rollback() throws SQLException {
        connectionUtils.getCurrentThreadConn().rollback();
    }
}

package com.learn.transfer.entity;

/**
 * Account  实体类
 * @author lijun
 */
public class Account {

    private String cardNo;
    private String name;
    private int money;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public String getCardNo() { return cardNo; }

    public void setCardNo(String cardNo) { this.cardNo = cardNo;}
}


package com.learn.transfer.entity;

/**
 * Result 实体类
 * @author lijun
 */
public class Result{

    private String status;
    private String message;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}
package com.learn.transfer.factory;

import com.alibaba.druid.util.StringUtils;
import com.learn.transfer.annotation.MyAutowired;
import com.learn.transfer.annotation.MyService;
import com.learn.transfer.annotation.MyTransactional;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @ClassName BeanFactory
 * @Description TODO
 * @Author lijun
 * @Date 2020/9/29 10:21
 */
public class BeanFactory {

    // 存储对象
    private static Map<String,Object> map = new HashMap<>();

    static{
        try{
            //扫描包,分析需实例化的对象列表(service和事务管理器),通过反射技术实例化对象并且存储待用(map集合)
            //扫描获取反射对象集合
            Reflections f = new Reflections("com.learn.transfer");
            //获取注解为service的集合
            Set<Class<?>> set = f.getTypesAnnotatedWith(MyService.class);
            for (Class<?> c : set) {
                // 通过反射技术实例化对象
                Object bean = c.newInstance();
                MyService annotation = c.getAnnotation(MyService.class);

                //对象ID在service注解有value时用value,没有时用类名
                if(StringUtils.isEmpty(annotation.value())){
                    //由于getName获取的是全限定类名,所以要分割去掉前面包名部分
                    String[] names = c.getName().split("\\.");
                    map.put(names[names.length-1], bean);
                }else{
                    map.put(annotation.value(), bean);
                }
            }
            // 实例化完成之后维护对象的依赖关系,检查哪些对象需要传值进入,根据它的配置,我们传入相应的值
            for(Map.Entry<String, Object> a:map.entrySet()){
                Object o = a.getValue();
                Class c = o.getClass();
                //获取属性集合
                Field[] fields = c.getDeclaredFields();
                //遍历属性,若持有Autowired注解则注入
                for (Field field : fields) {
                    if (field.isAnnotationPresent(MyAutowired.class)
                            &&field.getAnnotation(MyAutowired.class).value()) {
                        String[] names = field.getType().getName().split("\\.");
                        String name = names[names.length-1];
                        Method[] methods = c.getMethods();
                        for (int j = 0; j < methods.length; j++) {
                            Method method = methods[j];
                            // 该方法就是 setAccountDao(AccountDao accountDao)
                            if(method.getName().equalsIgnoreCase("set" + name)) {
                                method.invoke(o,map.get(name));
                            }
                        }
                    }
                }
                //判断对象类是否持有Transactional注解,若有则修改对象为代理对象
                if(c.isAnnotationPresent(MyTransactional.class)){
                    //获取代理工厂
                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                    //判断对象是否实现接口
                    //获取类c实现的所有接口
                    Class[] face = c.getInterfaces();
                    if(face!=null&&face.length>0){
                        //实现使用JDK
                        o = proxyFactory.getJdkProxy(o);
                    }else{
                        //没实现使用CGLIB
                        o = proxyFactory.getCglibProxy(o);
                    }
                }
                // 把处理之后的object重新放到map中
                map.put(a.getKey(),o);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 对外提供获取实例对象的接口(根据id获取)
     *
     * @Description: TODO
     * @Param: [id]
     * @Return: java.lang.Object
     * @Author: lijun
     * @Date: 2020/9/29
     **/
    public static  Object getBean(String id) {
        return map.get(id);
    }
}

package com.learn.transfer.factory;

import com.learn.transfer.annotation.MyAutowired;
import com.learn.transfer.annotation.MyService;
import com.learn.transfer.utils.TransactionManager;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @ClassName ProxyFactory
 * @Description TODO
 * @Author lijun
 * @Date 2020/9/29 10:21
 */
@MyService("proxyFactory")
public class ProxyFactory {

    @MyAutowired
    private TransactionManager transactionManager;

    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    /**
     * Jdk动态代理
     *
     * @Description: TODO
     * @Param: [obj]
     * @Return: java.lang.Object
     * @Author: lijun
     * @Date: 2020/9/29
     **/
    public Object getJdkProxy(Object obj) {
        // 获取代理对象
        return  Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Object result = null;
                    try{
                        // 开启事务(关闭事务的自动提交)
                        transactionManager.beginTransaction();
                        result = method.invoke(obj,args);
                        // 提交事务
                        transactionManager.commit();
                    }catch (Exception e) {
                        e.printStackTrace();
                        // 回滚事务
                        transactionManager.rollback();
                        // 抛出异常便于上层servlet捕获
                        throw e;
                    }
                    return result;
                }
        });
    }

    /**
     * 使用cglib动态代理生成代理对象
     *
     * @Description: TODO
     * @Param: [obj] 委托对象
     * @Return: java.lang.Object
     * @Author: lijun
     * @Date: 2020/9/29
     **/
    public Object getCglibProxy(Object obj) {
        return  Enhancer.create(obj.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object result = null;
                try{
                    // 开启事务(关闭事务的自动提交)
                    transactionManager.beginTransaction();
                    result = method.invoke(obj,objects);
                    // 提交事务
                    transactionManager.commit();
                }catch (Exception e) {
                    e.printStackTrace();
                    // 回滚事务
                    transactionManager.rollback();
                    // 抛出异常便于上层servlet捕获
                    throw e;
                }
                return result;
            }
        });
    }
}
时序图.png
上一篇 下一篇

猜你喜欢

热点阅读