Spring学习笔记2

目录

  • [1. 代理](#1. 代理)
    • [1.1 **JDK 动态代理**](#1.1 JDK 动态代理)
    • [1.2 **CGLIB 代理**](#1.2 CGLIB 代理)
    • [1.3 JDK 动态代理与 CGLIB 的对比](#1.3 JDK 动态代理与 CGLIB 的对比)
  • [2. AOP思想](#2. AOP思想)
    • [2.1 基本概念](#2.1 基本概念)
    • [2.2 AspectJ 技术](#2.2 AspectJ 技术)
    • [2.3 **AspectJ 使用 XML 配置**](#2.3 AspectJ 使用 XML 配置)
    • [2.4 **AspectJ 使用注解配置**](#2.4 AspectJ 使用注解配置)
    • [2.5 通知](#2.5 通知)
  • [3. JdbcTemplate](#3. JdbcTemplate)
    • [3.1 **主要特点**](#3.1 主要特点)
    • [3.2 **核心方法**](#3.2 核心方法)
    • [3.3 **使用步骤**](#3.3 使用步骤)
    • [3.4 **优点**](#3.4 优点)
  • [4. 配置平台事务管理器和事务管理模板](#4. 配置平台事务管理器和事务管理模板)
    • [4.1 配置平台事务管理器](#4.1 配置平台事务管理器)
    • [4.2 配置事务管理模板](#4.2 配置事务管理模板)
      • [4.2.1 编程式事务管理](#4.2.1 编程式事务管理)
      • [4.2.2 声明式事务管理](#4.2.2 声明式事务管理)

1. 代理

1.1 JDK 动态代理

JDK 动态代理是 Java 标准库自带的一种代理机制,基于 接口 实现。它的核心是 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。

特点

  • 基于接口:JDK 动态代理只能代理实现了接口的目标对象。
  • 性能较低:相较于 CGLIB,JDK 动态代理在运行时的性能稍低。
  • 灵活性高:可以在运行时动态生成代理类,适用于需要动态增强接口方法的场景。

实现步骤

  1. 定义接口:目标对象需要实现一个接口。
  2. 实现 InvocationHandler:用于处理代理类的方法调用。
  3. 生成代理对象 :通过 Proxy.newProxyInstance() 方法生成代理对象。

示例代码

  1. 定义接口
java 复制代码
public interface BankService {
    void transferMoney(Long fromAccountId, Long toAccountId, double amount);
}
  1. 实现目标类
java 复制代码
public class BankServiceImpl implements BankService {
    @Override
    public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
        System.out.println("Transferring money from account " + fromAccountId + " to account " + toAccountId);
    }
}
  1. 实现 InvocationHandler
java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TransactionHandler implements InvocationHandler {

    private Object target; // 目标对象

    public TransactionHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 事务控制逻辑
        System.out.println("Transaction started...");
        try {
            Object result = method.invoke(target, args); // 调用目标方法
            System.out.println("Transaction committed.");
            return result;
        } catch (Exception e) {
            System.out.println("Transaction rolled back.");
            throw e;
        }
    }
}
  1. 生成代理对象
java 复制代码
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        // 目标对象
        BankService target = new BankServiceImpl();

        // 创建 InvocationHandler
        TransactionHandler handler = new TransactionHandler(target);

        // 生成代理对象
        BankService proxy = (BankService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(), // 类加载器
            target.getClass().getInterfaces(), // 目标类实现的接口
            handler // InvocationHandler
        );

        // 调用代理对象的方法
        proxy.transferMoney(1L, 2L, 100.0);
    }
}

输出结果

Transaction started...
Transferring money from account 1 to account 2
Transaction committed.

1.2 CGLIB 代理

CGLIB(Code Generation Library)是一种基于 字节码生成 的代理技术,允许代理 没有实现接口的类 。它的核心是 net.sf.cglib.proxy.Enhancer 类和 net.sf.cglib.proxy.MethodInterceptor 接口。

特点

  • 基于类:CGLIB 可以代理没有实现接口的类。
  • 性能较高:CGLIB 生成的代理类直接基于目标类的字节码,性能通常优于 JDK 动态代理。
  • 动态生成子类 :CGLIB 通过生成目标类的子类来实现代理。
    实现步骤
  1. 定义目标类:目标类不需要实现接口。
  2. 实现 MethodInterceptor:用于处理代理类的方法调用。
  3. 生成代理对象 :通过 Enhancer 类生成代理对象。

示例代码

  1. 定义目标类
java 复制代码
public class BankService {
    public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
        System.out.println("Transferring money from account " + fromAccountId + " to account " + toAccountId);
    }
}
  1. 实现 MethodInterceptor
java 复制代码
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class TransactionInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 事务控制逻辑
        System.out.println("Transaction started...");
        try {
            Object result = proxy.invokeSuper(obj, args); // 调用目标方法
            System.out.println("Transaction committed.");
            return result;
        } catch (Exception e) {
            System.out.println("Transaction rolled back.");
            throw e;
        }
    }
}
  1. 生成代理对象
java 复制代码
import net.sf.cglib.proxy.Enhancer;

public class Main {
    public static void main(String[] args) {
        // 创建 Enhancer 对象
        Enhancer enhancer = new Enhancer();

        // 设置目标类的父类
        enhancer.setSuperclass(BankService.class);

        // 设置 MethodInterceptor
        enhancer.setCallback(new TransactionInterceptor());

        // 生成代理对象
        BankService proxy = (BankService) enhancer.create();

        // 调用代理对象的方法
        proxy.transferMoney(1L, 2L, 100.0);
    }
}

输出结果

Transaction started...
Transferring money from account 1 to account 2
Transaction committed.

1.3 JDK 动态代理与 CGLIB 的对比

特性 JDK 动态代理 CGLIB 代理
基于 接口
性能 较低(基于反射) 较高(基于字节码生成)
目标对象 必须实现接口 可以是任意类
代理对象 代理接口 生成目标类的子类
适用场景 需要代理接口方法 需要代理没有接口的类
依赖 JDK 自带 需要额外依赖 CGLIB 库

2. AOP思想

2.1 基本概念

AOP(Aspect-Oriented Programming) 是一种编程范式,旨在通过将横切关注点(Cross-Cutting Concerns)从核心业务逻辑中分离出来,提高代码的模块化程度。横切关注点是指那些在多个模块中都会用到的功能,例如日志记录、事务管理、安全性检查等。AOP 的核心思想是将这些横切关注点从核心业务逻辑中解耦,封装成独立的模块(切面),并通过配置或注解的方式,将它们动态地应用到需要增强的类或方法上。

AOP 的关键术语

  1. 切面(Aspect):模块化的横切关注点,例如日志记录、事务管理等。
  2. 连接点(Join Point):程序执行过程中的某个点,例如方法调用、异常抛出等。
  3. 通知(Advice):切面在特定的连接点上执行的动作,例如在方法调用前后执行的日志记录。
  4. 切点(Pointcut) :定义了通知应该应用到哪些连接点的规则,例如所有以 transferMoney 开头的方法。
  5. 引入(Introduction):允许向现有的类添加新方法或属性。
  6. 织入(Weaving):将切面应用到目标对象的过程,可以在编译时、类加载时或运行时进行。

2.2 AspectJ 技术

AspectJ 是一个成熟的 AOP 框架,提供了丰富的语法和工具,支持在 Java 应用中实现 AOP。AspectJ 可以在编译时或运行时将切面织入到目标类中。

AspectJ 的主要特点

  1. 强大的定义切点的能力:AspectJ 提供了灵活的切点表达式,可以精确地指定通知应该应用到哪些方法或代码块。
  2. 多种通知类型:支持多种通知类型,包括前置通知(Before)、后置通知(After)、环绕通知(Around)等。
  3. 编译时织入:可以在编译时将切面织入到目标类中,提高运行时性能。
  4. 运行时织入:也可以在运行时通过代理或字节码操作将切面织入到目标类中。
  5. 丰富的注解和 XML 配置:支持通过注解或 XML 配置来定义切面和切点。

2.3 AspectJ 使用 XML 配置

添加 AspectJ 依赖

如果使用 Maven,在 pom.xml 中添加 AspectJ 的依赖。

xml 复制代码
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.7</version>
</dependency>

实例代码

1. 切面类

java 复制代码
public class LoggingAspect {

    // 前置通知
    public void logBefore() {
        System.out.println("Logging before method execution");
    }
}

2. 目标类

java 复制代码
package com.example.service;

public class BankService {

    public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
        System.out.println("Transferring money from account " + fromAccountId + " to account " + toAccountId);
    }
}

3. XML 配置文件

在 XML 配置文件中定义切面、切点和通知:

xml 复制代码
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 定义目标 bean -->
    <bean id="bankService" class="com.example.service.BankService" />

    <!-- 定义切面 bean -->
    <bean id="loggingAspect" class="com.example.aspect.LoggingAspect" />

    <!-- 定义切面 -->
    <aop:config>
        <!-- 定义切点 -->
        <aop:pointcut id="serviceMethods" expression="execution(* com.example.service.*.*(..))"/>

        <!-- 定义切面和通知 -->
        <aop:aspect ref="loggingAspect">
            <aop:before pointcut-ref="serviceMethods" method="logBefore"/>
        </aop:aspect>
    </aop:config>
</beans>

4. 测试代码

java 复制代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BankService bankService = context.getBean(BankService.class);
        bankService.transferMoney(1L, 2L, 100.0);
    }
}

输出结果

Logging before method execution
Transferring money from account 1 to account 2

2.4 AspectJ 使用注解配置

添加 AspectJ 依赖

如果使用 Maven,在 pom.xml 中添加 AspectJ 的依赖。

xml 复制代码
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.7</version>
</dependency>

实例代码

1. 切面类

java 复制代码
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect  // 标记这是一个切面
public class LoggingAspect {

    // 定义切点
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}

    // 定义前置通知
    @Before("serviceMethods()")
    public void logBefore() {
        System.out.println("Logging before method execution");
    }
}

2. 目标类

java 复制代码
package com.example.service;

public class BankService {

    public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
        System.out.println("Transferring money from account " + fromAccountId + " to account " + toAccountId);
    }
}

3. Spring 配置文件

如果使用 Spring,需要在 Spring 的 XML 配置文件中启用注解支持:

xml 复制代码
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 启用 AspectJ 注解支持 -->
    <aop:aspectj-autoproxy/>

    <!-- 定义切面 bean -->
    <bean id="loggingAspect" class="com.example.aspect.LoggingAspect" />

    <!-- 定义目标 bean -->
    <bean id="bankService" class="com.example.service.BankService" />
</beans>

4. 测试代码

java 复制代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BankService bankService = context.getBean(BankService.class);
        bankService.transferMoney(1L, 2L, 100.0);
    }
}

输出结果

Logging before method execution
Transferring money from account 1 to account 2

2.5 通知

AspectJ 提供了多种通知(Advice)类型,每种通知类型在不同的连接点(Join Point)上执行不同的逻辑。以下是 AspectJ 中常见的通知类型及其作用和语法。

1. Before 通知(前置通知)

  • 作用:在目标方法执行之前执行。
  • 语法
java 复制代码
@Aspect
public class BeforeAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}

    @Before("serviceMethods()")  // 前置通知
    public void beforeAdvice() {
        System.out.println("Before advice executed");
    }
}

2. After 通知(后置通知)

  • 作用:在目标方法执行之后执行(无论方法是否抛出异常)。
  • 语法
java 复制代码
@Aspect
public class AfterAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}

    @After("serviceMethods()")  // 后置通知
    public void afterAdvice() {
        System.out.println("After advice executed");
    }
}

3. AfterReturning 通知(返回通知)

  • 作用:在目标方法成功返回且没有抛出异常时执行。
  • 语法
java 复制代码
@Aspect
public class AfterReturningAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}

    @AfterReturning(pointcut = "serviceMethods()", returning = "result")  // 返回通知
    public void afterReturningAdvice(Object result) {
        System.out.println("AfterReturning advice executed. Result: " + result);
    }
}
  • 参数说明
    • returning = "result":将方法返回值绑定到通知方法的参数 result

4. AfterThrowing 通知(异常通知)

  • 作用:在目标方法抛出异常时执行。
  • 语法
java 复制代码
@Aspect
public class AfterThrowingAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}

    @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")  // 异常通知
    public void afterThrowingAdvice(Exception ex) {
        System.out.println("AfterThrowing advice executed. Exception: " + ex.getMessage());
    }
}
  • 参数说明
    • throwing = "ex":将异常对象绑定到通知方法的参数 ex

5. Around 通知(环绕通知)

  • 作用:在目标方法执行前后执行,并且可以完全控制方法的执行流程。
  • 语法
java 复制代码
@Aspect
public class AroundAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}

    @Around("serviceMethods()")  // 环绕通知
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around advice: Before method execution");

        // 调用目标方法
        Object result = joinPoint.proceed();

        System.out.println("Around advice: After method execution");
        return result;
    }
}
  • 关键点
    • ProceedingJoinPoint 是关键对象,调用其 proceed() 方法以执行目标方法。
    • 可以修改方法的返回值,或完全阻止方法的执行。

3. JdbcTemplate

JdbcTemplate 是 Spring 框架提供的一个核心工具类,用于简化 JDBC 操作。它封装了 JDBC 的繁琐操作(如连接管理、异常处理、资源释放等),使开发者能够更专注于 SQL 语句和业务逻辑的实现。

引入依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
</dependencies>

3.1 主要特点

  1. 简化 JDBC 操作

    • 自动管理数据库连接、语句和结果集的创建与释放。
    • 减少样板代码,提高开发效率。
  2. 统一的异常处理

    • 将 JDBC 的 SQLException 转换为 Spring 的 DataAccessException,提供更清晰的异常层次结构。
  3. 支持多种操作

    • 支持查询、更新、批量操作、存储过程调用等。
  4. 与 Spring 集成

    • 与 Spring 的事务管理、数据源等无缝集成。

3.2 核心方法

1. 更新操作(增删改)

  • update():用于执行 INSERT、UPDATE、DELETE 等 SQL 语句。

    java 复制代码
    int update(String sql, Object... args);

    示例:

    java 复制代码
    String sql = "UPDATE users SET name = ? WHERE id = ?";
    int rows = jdbcTemplate.update(sql, "John", 1);

2. 查询操作

  • queryForObject():查询单行数据并映射为对象。

    java 复制代码
    <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args);

    示例:

    java 复制代码
    String sql = "SELECT * FROM users WHERE id = ?";
    User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), 1);
  • query():查询多行数据并映射为对象列表。

    java 复制代码
    <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args);

    示例:

    java 复制代码
    String sql = "SELECT * FROM users";
    List<User> users = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));

3. 执行任意 SQL

  • execute():用于执行任意 SQL 语句(如 DDL 语句)。

    java 复制代码
    void execute(String sql);

    示例:

    java 复制代码
    jdbcTemplate.execute("CREATE TABLE users (id INT, name VARCHAR(100))");

3.3 使用步骤

  1. 配置数据源

    • 在 Spring 配置文件中配置数据源(如 DataSource)。

    • 示例:

      xml 复制代码
      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
          <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
          <property name="url" value="jdbc:mysql://localhost:3306/test"/>
          <property name="username" value="root"/>
          <property name="password" value="password"/>
      </bean>
  2. 创建 JdbcTemplate

    • 将数据源注入到 JdbcTemplate 中。

    • 示例:

      xml 复制代码
      <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
          <property name="dataSource" ref="dataSource"/>
      </bean>
  3. 在代码中使用

    • 通过依赖注入获取 JdbcTemplate 实例并调用其方法。

    • 示例:

      java 复制代码
      @Autowired
      private JdbcTemplate jdbcTemplate;
      
      public void addUser(User user) {
          String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
          jdbcTemplate.update(sql, user.getName(), user.getAge());
      }

3.4 优点

  1. 简化代码
    • 减少 JDBC 样板代码,提高开发效率。
  2. 异常处理
    • 提供统一的异常处理机制,避免繁琐的 try-catch 块。
  3. 与 Spring 集成
    • 与 Spring 的事务管理、数据源等无缝集成。
  4. 灵活性
    • 支持自定义 RowMapperResultSetExtractor,满足复杂需求。

4. 配置平台事务管理器和事务管理模板

在 Spring 框架中,事务管理是一个非常重要的功能,用于确保数据库操作的完整性。Spring 提供了多种事务管理方式,其中最常见的两种是声明式事务管理和编程式事务管理。

4.1 配置平台事务管理器

平台事务管理器是 Spring 事务管理的核心接口,它负责事务的开始、提交和回滚。最常见的实现是 DataSourceTransactionManager,用于管理 JDBC 数据源的事务。

  1. 配置数据源

首先,需要配置一个数据源。这里我们使用 DriverManagerDataSource 作为示例数据源:

xml 复制代码
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test"/>
    <property name="username" value="root"/>
    <property name="password" value="password"/>
</bean>
  1. 配置平台事务管理器

接下来,配置 DataSourceTransactionManager,将数据源注入到事务管理器中:

xml 复制代码
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

4.2 配置事务管理模板

事务管理模板(TransactionTemplate)是一个辅助类,用于简化事务管理的编程式操作。它可以自动管理事务的开始、提交和回滚。

配置事务管理模板

在 Spring 配置文件中配置 TransactionTemplate,并将平台事务管理器注入到模板中:

xml 复制代码
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
</bean>

4.2.1 编程式事务管理

使用 TransactionTemplate 进行编程式事务管理,可以通过 lambda 表达式或 TransactionCallback 接口来实现。

示例代码

java 复制代码
@Autowired
private TransactionTemplate transactionTemplate;

@Autowired
private JdbcTemplate jdbcTemplate;

public void addUser(User user) {
    transactionTemplate.execute(status -> {
        try {
            String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
            jdbcTemplate.update(sql, user.getName(), user.getAge());
            // 模拟异常
            // int i = 1 / 0;
            return null;
        } catch (Exception e) {
            // 回滚事务
            status.setRollbackOnly();
            throw e;
        }
    });
}

4.2.2 声明式事务管理

声明式事务管理通过在 Spring 配置文件中使用 AOP 配置事务,实现更简洁的事务管理。

  1. 配置事务管理器

确保已经配置了 DataSourceTransactionManager

  1. 配置事务管理器的 AOP 支持

使用 tx:annotation-driven 开启基于注解的事务管理:

xml 复制代码
<tx:annotation-driven transaction-manager="transactionManager"/>
  1. 使用 @Transactional 注解

在需要事务管理的类或方法上使用 @Transactional 注解:

java 复制代码
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    public void addUser(User user) {
        String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
        jdbcTemplate.update(sql, user.getName(), user.getAge());
        // 模拟异常
        // int i = 1 / 0;
    }
}
相关推荐
Miraitowa_cheems1 分钟前
[JavaEE] Spring IoC&DI
java·spring·java-ee
AH_HH27 分钟前
如何学习Vue设计模式
vue.js·学习·设计模式
雪碧透心凉_1 小时前
Win32汇编学习笔记09.SEH和反调试
汇编·笔记·学习
XWM_Web1 小时前
JavaAPI.02.包装类与正则表达式
java·开发语言·学习·eclipse
破浪前行·吴1 小时前
【初体验】【学习】Web Component
前端·javascript·css·学习·html
PangPiLoLo1 小时前
架构学习——互联网常用架构模板
java·学习·微服务·云原生·架构·系统架构·nosql
跳跳的向阳花2 小时前
05、Docker学习,常用安装:Mysql、Redis、Nginx、Nacos
学习·mysql·docker
serenity宁静2 小时前
Center Loss 和 ArcFace Loss 笔记
笔记·深度学习·机器学习
14_112 小时前
Cherno C++学习笔记 P51 创建并使用库
c++·笔记·学习
雨 子3 小时前
Spring Web MVC
前端·spring boot·spring·mvc·postman