手写@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容器功能;加上自定义事务注解,实现了事务功能。
- 如果需要视频讲解,私聊我,本人录制了运行效果展示和代码讲解视频。
手写@Service、@Autowired、@Transactional注解,实现spring ioc和spring事务的更多相关文章
- spring揭密学习笔记(3)-spring ioc容器:Spring的IoC容器之BeanFactory
1. Spring的IoC容器和IoC Service Provider的关系 Spring的IoC容器和IoC Service Provider所提供的服务之间存在一定的交集,二者的关系如图4-1所 ...
- Spring IOC和Spring AOP的实现原理(源码主线流程)
写在前面 正本文参考了<spring技术内幕>和spring 4.0.5源码.本文只描述原理流程的主线部分,其他比如验证,缓存什么可以具体参考源码理解. Spring IOC 一.容器初始 ...
- 【Spring IoC】Spring Bean(三)
一.Spring Bean的定义 被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的.bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象. ...
- Spring Boot中Service用@Transactional 注解
一般来说function2和function1用的是同一个Transaction. 这个取决于@Transactional 的 propagation设置(事务的传播性) 默认的是 1 @Transa ...
- spring ioc 原理 spring aop原理
大家一直都说spring的IOC如何如何的强大,其实我倒觉得不是IOC如何的强大,说白了IOC其实也非常的简单.我们先从IOC说起,这个概念其实是从我们平常new一个对象的对立面来说的,我们平常使用对 ...
- Spring - IoC(1): Spring 容器
BeanFactory & ApplicationContext org.springframework.beans.factory.BeanFactory 是最基本的 Spring 容器接口 ...
- spring IOC(Spring 生命周期,先1.构造方式,2,初始化方法,3,目标方法,4,销毁方法)
- Spring Boot 中使用 @Transactional 注解配置事务管理
事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP ...
- Spring对于事务的控制@Transactional注解详解
引用自:https://blog.csdn.net/fanxb92/article/details/81296005 先简单介绍一下Spring事务的传播行为: 所谓事务的传播行为是指,如果在开始当前 ...
随机推荐
- PHP timezone_name_from_abbr() 函数
------------恢复内容开始------------ 实例 根据时区缩略语返回时区名称: <?phpecho timezone_name_from_abbr("EST" ...
- PHP mysqli_sqlstate() 函数
返回最后一个 MySQL 操作的 SQLSTATE 错误代码: <?php 高佣联盟 www.cgewang.com // 假定数据库用户名:root,密码:123456,数据库:RUNOOB ...
- Ajax中关于xmlhttp.readyState的值及解释
xmlhttp.readyState的值及解释:0:请求未初始化(还没有调用 open()).1:请求已经建立,但是还没有发送(还没有调用 send()).2:请求已发送,正在处理中(通常现在可以从响 ...
- 提交项目到码云上git的使用
git clone .. cd 到项目目录 git branch 查看当前的所有分支 git branch shanshan 创建一个属于自己的分支 git checkout shansha ...
- JVM进行篇
结合字节码指令理解Java虚拟机栈和栈帧 栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的 ...
- python3.2求和与最值
#1到100求和sum1=0for x in range(101): sum1=sum1+xprint(sum1) #1到100偶数求和sum2=0for x in range(0,101,2): p ...
- 大学生可用来接单,利用Python实现教务系统扩容抢课!
最近一学期一次的抢课大戏又来了,几家欢乐几家愁.O(∩_∩)O哈哈~(l我每次一选就过了hah,我还是有欧的时候滴).看着他们盯着教务系统就着急,何况我们那教务系统,不想说什么.emmm 想周围的朋友 ...
- C# ASP 异步存储数据
1.异步委托 在导航栏接收到提交的请求后,调用个各子画面的保存答案方法,之后实例化委托 saveToDB . 当执行BeginInvoke后,服务器会另起线程执行saveToDB里的的方法,因为这里要 ...
- Visual-platform,基于Vue的可视化大屏开发GUI框架
visual-platform 基于Vue的可视化大屏开发GUI框架 ------ CreatedBy 漆黑小T 构建用于开发可视化大屏项目的自适应布局的GUI框架. github仓库: https: ...
- Homekit_DoHome_智能通断器
本款通断器适用于IOS和android系统用户,苹果用户可以非常方便的使用siri进行有效控制,android用户需要下载Dohome App进行操作,同时支持市面上主流的智能音箱进行控制. 对于an ...