手写@Service、@Autowired、@Transactional注解,实现spring ioc和spring事务

自定义@Service注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomService {
    String value() default "";
}

自定义@Autowired注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAutowired {
}

自定义@Transactional注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomTransactional {
}

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

  • controller层
@WebServlet(name="transferServlet",urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {

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

        CustomApplicationContext customApplicationContext = new CustomApplicationContext("com.zhu.yuandi");
        transferService = (TransferService) customApplicationContext.getBean("TransferService",customApplicationContext);

        // 设置请求体的字符编码
        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 {
            //调用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));
    }
}
  • service层
public interface TransferService {
    void transfer(String fromCardNo,String toCardNo,int money) throws Exception;
}

@CustomService(value = "transferService")
@CustomTransactional
public class TransferServiceImpl implements TransferService {
    @CustomAutowired
    private AccountDao accountDao;
    
    @Override
    public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {
            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);
    }
}
  • dao层
public interface AccountDao {
    Account queryAccountByCardNo(String cardNo) throws Exception;
    int updateAccountByCardNo(Account account) throws Exception;
}

@CustomService
public class JdbcAccountDaoImpl implements AccountDao {
    @CustomAutowired
    private ConnectionUtils connectionUtils;
    
    @Override
    public Account queryAccountByCardNo(String cardNo) throws Exception {
        Connection con = connectionUtils.getCurrentThreadConn();
        String sql = "select * from 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();
        return account;
    }
    
    @Override
    public int updateAccountByCardNo(Account account) throws Exception {
        Connection con = connectionUtils.getCurrentThreadConn();
        String sql = "update 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();
        return i;
    }
}

开发中用到的数据库Utils、动态代理Utils等其他相关类

@CustomService
public class ConnectionUtils {
    
    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;

    }
}

public class DruidUtils {
    private DruidUtils(){
    }
    private static DruidDataSource druidDataSource = new DruidDataSource();
    static {
        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/bank?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Hongkong");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");

    }
    public static DruidDataSource getInstance() {
        return druidDataSource;
    }
}

@CustomService
public class ProxyFactory {
    
    @CustomAutowired
    private TransactionManager transactionManager;
    
    /**
     * Jdk动态代理
     * @param obj  委托对象
     * @return   代理对象
     */
    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;
                    }
                });

    }
}

@CustomService
public class TransactionManager {

    @CustomAutowired
    private ConnectionUtils connectionUtils;

    // 开启手动事务控制
    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();
    }
}

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

    @Override
    public String toString() {
        return "Account{" +
                "cardNo='" + cardNo + '\'' +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

注解解析类

public class CustomApplicationContext {
    //包名
    private String packageName;
    private ConcurrentHashMap<String, Object> beans = new ConcurrentHashMap<>();
    
    public CustomApplicationContext(String packageName) {
        this.packageName = packageName;
        initBeans();
    }

    private void initBeans() {
        List<Class> classList = getClasses(packageName);
        findClassIsAddedCostomAnnotation(classList);
    }
    
    private List<Class> getClasses(String packageName) {
        List<Class> classList = new ArrayList<>();
        String packageDirName = packageName.replace(".", "/");
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if (protocol.equals("file")) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    findAndAddClassesInPackageByFile(packageName, filePath, classList);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classList;
    }

    private void findAndAddClassesInPackageByFile(String packageName, String filePath, List<Class> classList) {
        File dir = new File(filePath);
        //选出文件夹下面所有的文件
        File[] files = dir.listFiles(new FileFilter() {
            public boolean accept(File file) {
                return (file.isDirectory() || file.getName().endsWith(".class"));
            }
        });
        for (File file : files) {
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), classList);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    classList.add(Class.forName(packageName + "." + className));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    private void findClassIsAddedCostomAnnotation(List<Class> classList) {
        try{
            for (Class aClass : classList) {
                classToObjectIntoBeans(aClass, classList);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void classToObjectIntoBeans(Class aClass, List<Class> classList) {
        Object obj = null;

        try{
            if(aClass.isInterface()){
                for(Class implClass : classList) {
                    if (implClass.isInterface()) {
                        continue;
                    }
                    Class fieldClassCopy = implClass.getClassLoader().loadClass(aClass.getName());
                    if (fieldClassCopy.isAssignableFrom(implClass)) {
                        Constructor[] constructors = implClass.getConstructors();
                        for(Constructor constructor : constructors){
                            int parameterCount = constructor.getParameterCount();
                            if(parameterCount==0){
                                obj = constructor.newInstance();
                            }
                        }
                        break;
                    }
                }
            } else {
                Constructor[] constructors = aClass.getConstructors();
                for(Constructor constructor : constructors){
                    int parameterCount = constructor.getParameterCount();
                    if(parameterCount==0){
                        obj = constructor.newInstance();
                    }
                }
            }
            if (obj != null) {
                beans.put(aClass.getSimpleName(), obj);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    public Object getBean(String beanName,CustomApplicationContext customApplicationContext) {
        Object beanObject = beans.get(beanName);
        try{
            referenceBindObject(beanObject);
        }catch (Exception e){
            e.printStackTrace();
        }

        Class aClass = beanObject.getClass();
        Annotation annotation = aClass.getAnnotation(CustomTransactional.class);
        if (annotation != null) {
            ProxyFactory proxyFactory = (ProxyFactory) customApplicationContext.getBean("ProxyFactory", customApplicationContext);
            beanObject = proxyFactory.getJdkProxy(beanObject);
        }
        return beanObject;
    }
    
    private Object referenceBindObject(Object beanObject) {
        Class beanClass = beanObject.getClass();
        Field[] declaredFields = beanClass.getDeclaredFields();
        try {
            for (Field field : declaredFields) {
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }
                CustomAutowired filedAnnotation = field.getAnnotation(CustomAutowired.class);
                if (filedAnnotation == null) {
                    System.out.println(beanClass.getName() + "类中的" + field.getName() + "字段,该字段上没有加注解");
                    break;
                }
                Class fieldClass = field.getType();
                String classSimpleName = fieldClass.getSimpleName();
                Object fieldObject = beans.get(classSimpleName);
                Object object = referenceBindObject(fieldObject);
                field.set(beanObject, object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return beanObject;
    }

}
  • 以上,我们完成了自定义注解,实现了spring ioc容器功能;加上自定义事务注解,实现了事务功能。
  • 如果需要视频讲解,私聊我,本人录制了运行效果展示和代码讲解视频。
posted @ 2020-08-11 10:20  队长别开枪&nbsp;是我  阅读(1536)  评论(4编辑  收藏  举报