自定义@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 "";
}
2. 自定义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;
}
3. 自定义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层 代码
controller层
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));
}
}
service接口层和实现层
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;
}
}
}
dao接口层和实现层
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);
}
}
开发中用到的数据库Utils、动态代理Utils等其他相关类
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;
}
}
注解解析类BeanFactory
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;
}
});
}
}