【MyBatis】| 使⽤javassist⽣成类、面向接口的方式进行CRUD

news2024/11/15 13:36:46

目录

一:使⽤javassist⽣成类

1. Javassist的使⽤

2.  动态生成类并实现接口

 3. MyBatis中接⼝代理机制及使⽤

 二:面向接口的方式进行CRUD


一:使⽤javassist⽣成类

Javassist是⼀个开源的分析、编辑和创建Java字节码的类库。是由东京⼯业⼤学的数学和计算机科学 系的 Shigeru Chiba (千叶 滋)所创建的。它已加⼊了开放源代码JBoss 应⽤服务器项⽬,通过使⽤ Javassist对字节码操作为JBoss实现动态"AOP"框架(面向切面编程)。

1. Javassist的使⽤

(1)引入javassist依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bjpowernode</groupId>
    <artifactId>javassist-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--javassist依赖-->
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.20.0-GA</version>
        </dependency>
        <!--junit依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

</project>

(2)编写测试类

①先调用ClassPool.getDefault()方法获取类池pool,通过这个类池用来生成class

②调用类池pool的

makeClass方法制造类,参数用来指定类名

③有了类就可以调用CtMethod.make方法制造方法,第一个参数是定义的方法,第二个参数是制造的类

④调用制造类的addMethod方法,将方法添加到类中

⑤调用制造类的toClass()方法,在内存中生成class

⑥通过反射机制,调用方法

package com.bjpowernode.javassist;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.javassist
 * @Project:mybatis
 * @name:JavassistTest
 * @Date:2023/1/2 14:38
 */
public class JavassistTest {
    @Test
    public void testGenerateFirstClass() throws Exception {
        // 获取类池,这个类池就是用来生成class的
        ClassPool pool = ClassPool.getDefault();
        // 制造类(告诉javassist类名是啥)
        CtClass ctClass = pool.makeClass("com.bjpowernode.bank.dao.impl.AccountDaoImpl");
        // 制造方法
        String methodCode = "public void insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode, ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成class
        ctClass.toClass();

        // 调用方法,以下都是反射机制的知识点
        // 类加载到JVM当中,返回AccountDaoImpl的字节码
        Class<?> clazz = Class.forName("com.bjpowernode.bank.dao.impl.AccountDaoImpl");
        // 创建对象
        Object obj = clazz.newInstance();
        // 获取AccountDaoImpl中的insert方法
        Method insertMethod = clazz.getDeclaredMethod("insert");
        // 调用obj的insert方法
        insertMethod.invoke(obj);
    }
}

JDK8之后运⾏要注意:加两个参数,要不然会有异常。

①--add-opens java.base/java.lang=ALL-UNNAMED

②--add-opens java.base/sun.net.util=ALL-UNNAMED

2.  动态生成类并实现接口

(1)先定义一个接口

package com.bjpowernode.ban.dao;

public interface AccountDao {
    void delete();
}

(2)使用javassist动态生成类并实现接口,和上面的代码很类似,主要是在添加方法之前,制造上面的接口到内存当中,然后把这个接口添加到类当中即可。

注意1:ctClass.addInterface(ctInterface);把接口添加都类当中,实际上就等价于AccountDaoImpl implements AccountDao

注意2:ctClass.toClass()实际上有两个功能:一是在内存中生成类,二是同时将生成的类加载到JVM当中。

package com.bjpowernode.javassist;

import com.bjpowernode.ban.dao.AccountDao;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.javassist
 * @Project:mybatis
 * @name:JavassistTest
 * @Date:2023/1/2 14:38
 */
public class JavassistTest {
    @Test
    public void testGenerateImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.bjpowernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.bjpowernode.ban.dao.AccountDao");
        // 添加接口到类中
        ctClass.addInterface(ctInterface);
        // 实现接口中的方法
        // 制造方法
        CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"Hello World\");}", ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类,同时将生成的类加载到JVM当中
        Class clazz = ctClass.toClass(); // 等价于上面的两行代码
        AccountDao accountDao = (AccountDao) clazz.newInstance(); // 强转,面向接口编程
        accountDao.delete();
    }

}

(3)上面我们是已知接口中有一个类,所以在制造方法时写死了;但如果不知道接口中有多少个方法呢?怎么实现接口中所有的方法?

①接口中有多个方法

package com.bjpowernode.ban.dao;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.ban.dao
 * @Project:mybatis
 * @name:AccountDao
 * @Date:2023/1/2 15:36
 */
public interface AccountDao {
    void delete();
    int insert(String actno);
    int update(String actno,Double balance);
    String selectByActno(String actno);
}

②动态的实现所有的方法,主要利用反射机制,进行代码的拼接

package com.bjpowernode.javassist;

import com.bjpowernode.ban.dao.AccountDao;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.javassist
 * @Project:mybatis
 * @name:JavassistTest
 * @Date:2023/1/2 14:38
 */
public class JavassistTest {

    @Test
    public void testGenerateAccountDaoImpl() throws Exception {
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.bjpowernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.bjpowernode.ban.dao.AccountDao");
        // 实现接口
        ctClass.addInterface(ctInterface);
        // 实现接口中所有的方法
        // 获取接口中所有的方法
        Method[] methods = AccountDao.class.getDeclaredMethods();
        for (Method method:methods){
            // 把抽象方法实现了
            CtMethod ctMethod = null;
            try {
                // 拼出methodCode的方法
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public "); // 追加修饰符列表
                methodCode.append(method.getReturnType().getSimpleName()); // 追加返回值类型
                methodCode.append(" ");
                methodCode.append(method.getName()); // 追加方法名
                methodCode.append("(");
                // 拼接参数类型
                Class<?>[] parameterTypes = method.getParameterTypes(); // 获取到所有的参数类型
                for (int i = 0; i <parameterTypes.length ; i++) { // 遍历这个数组
                    // 遍历,取出每个进行遍历拼接
                    Class<?> parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getSimpleName()); // 拼接参数类型
                    methodCode.append(" ");
                    methodCode.append("arg"+i); // 拼接变量名,使用下标防止变量名冲突
                    if (i != parameterTypes.length-1){ // 如果不是最后一个参数,就加上逗号
                        methodCode.append(",");
                    }
                }
                methodCode.append("){System.out.println(1111);");
                // 添加返回值类型 return语句
                String returnTypeSimpleName = method.getReturnType().getSimpleName();
                if ("void".equals(returnTypeSimpleName)) {
                    // 什么都不做
                }else if ("int".equals(returnTypeSimpleName)){
                    methodCode.append("return 1;");
                }else if("String".equals(returnTypeSimpleName)){
                    methodCode.append("return \"Hello\";");
                }
                methodCode.append("}");
                // System.out.println(methodCode);
                ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        // 在内存中生成class,并且加载到JVM当中
        Class clazz = ctClass.toClass();
        // 创建对象
        AccountDao accountDao = (AccountDao) clazz.newInstance();
        // 调用方法
        accountDao.insert("111");
        accountDao.delete();
        accountDao.update("111",1000.0);
        accountDao.selectByActno("111");
    }

}

(4)所以对于AccountDao的实现类AccountDaoImpl就不用手动写了,利用javassist编写一个工具类GenerateDaoProxy,用来动态生成AccountDaoImpl。

注意:实际上Mybatis已经内置了javassist,直接使用即可,不需要在引入javassist依赖。

重点:sql语句的id是框架使用者提供的,具有多变性。对于框架的开发人员来说,不知道。
既然框架开发者不知道sqlId,怎么办呢?mybatis框架的开发者于是就出台了一个规定:凡是使用GenerateDaoProxy机制的:sqlId都不能随便写,namespace必须是dao接口的全限定名称,id必须是dao接口中方法名。

①要动态生成的类

package com.bjpowernode.bank.bao.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;


public class AccountDaoImpl implements AccountDao {
    @Override
    public Account selectByActno(String actno) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
      /*  Account account = (Account) sqlSession.selectOne("account.selectByActno", actno);
        return account;*/
        return (Account) sqlSession.selectOne("account.selectByActno", actno);
    }

    @Override
    public int updateByActno(Account act) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        /*int count = sqlSession.update("account.updateByActno", act);
        return count;*/
        return sqlSession.update("account.updateByActno", act);
    }
}

②修改专门编写sql语句的AccountMapper.xml文件:namespace修改为dao接口的全限定名称,id修改为dao接口中方法名

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.bjpowernode.bank.bao.AccountDao">
    <select id="selectByActno" resultType="com.bjpowernode.bank.pojo.Account">
        select * from t_act where actno=#{actno}
    </select>

    <update id="updateByActno">
        update t_act set balance = #{balance} where actno = #{actno};
    </update>
</mapper>

③ GenerateDaoProxy工具类,专门用来动态实现Dao接口的实现类的

package com.bjpowernode.bank.utils;

import org.apache.ibatis.javassist.CannotCompileException;
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtMethod;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.SqlSession;

import java.lang.reflect.Method;

/**
 * 工具类:可以动态的生成DAO的实现类
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.utils
 * @Project:mybatis
 * @name:GenerateDaoProxy
 * @Date:2023/1/2 19:42
 */
public class GenerateDaoProxy {
    /**
     * 生成dao接口的实现类,并且将实现类的对象创建出来并返回
     * @param daoInterface
     * @return dao接口实现类的实例化对象
     */
    public static Object generate(SqlSession sqlSession,Class daoInterface){ // 参数传一个接口
        // 类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass(daoInterface.getName() + "Impl"); // 实际本质上就是在内存中动态生成一个代理类
        // 制造接口
        CtClass ctInterface = pool.makeInterface(daoInterface.getName());
        // 实现接口
        ctClass.addInterface(ctInterface);
        // 实现接口中的方法
        Method[] methods = daoInterface.getDeclaredMethods();
        for (Method method : methods){
            // 拼方法
            StringBuilder methodCode = new StringBuilder();
            methodCode.append("public");
            methodCode.append(method.getReturnType().getName());
            methodCode.append(" ");
            methodCode.append(method.getName());
            methodCode.append("(");
            // 方法的形式参数列表
            Class<?>[] parameterTypes = method.getParameterTypes();
            for (int i = 0; i < parameterTypes.length; i++) {
                Class<?> parameterType = parameterTypes[i];
                methodCode.append(parameterType.getName());
                methodCode.append(" ");
                methodCode.append("arg"+i);
                if (i != parameterTypes.length-1){
                    methodCode.append(",");
                }
            }
            methodCode.append(")");
            methodCode.append("{");
            // 需要方法体当中的代码
            // 第一行代码是都相同的,注意要带上包名
            methodCode.append("org.apache.ibatis.session.SqlSession sqlSession = com.bjpowernode.bank.utils.SqlSessionUtils.openSession();");
            // 第二行代码要先需要知道是什么类型的sql语句
            // SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sql语句的id).getSqlCommandType();
            // 现在关键问题就是如何获得sql语句的id?
            // 获取sqlId(这⾥⾮常重要:因为这⾏代码导致以后namespace必须是接⼝的全
            // 限定接⼝名,sqlId必须是接⼝中⽅法的⽅法名。)
            String sqlId = daoInterface.getName() + "." + method.getName();
            SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType();
            if (sqlCommandType == SqlCommandType.INSERT) {

            }
            if (sqlCommandType == SqlCommandType.DELETE) {

            }
            if (sqlCommandType == SqlCommandType.UPDATE) {
                // 变量名上面我们拼接用的是arg加下标,这里应该是arg0
                methodCode.append("return sqlSession.update(\""+sqlId+"\", arg0);");
            }
            if (sqlCommandType == SqlCommandType.SELECT) {
                // 动态获取强转的类型
                String returnType = method.getReturnType().getName();
                methodCode.append("return ("+returnType+")sqlSession.selectOne(\""+sqlId+"\", arg0);");
            }


            methodCode.append("}");
            try {
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


        // 创建对象
        Object obj = null;
        try {
            Class<?> clazz = ctClass.toClass();
            obj = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return obj;
    }
}

④Service调用实现类,原来是实现了 AccountDaoImpl类,Service通过new的方式创建;现在是通过上面的工具类 GenerateDaoProxy来创建对象

 3. MyBatis中接⼝代理机制及使⽤

(1)幸运的是对于GenerateDaoProxy功能的实现,Mybatis框架已经封装好了,在Mybatis当中实际上采用了代理模式。在内存中生成dao接口的代理类,然后创建代理类的实例。

(2)使用Mybatis的这种代理机制的前提:SqlMapper.xml文件中namespace必须是dao接口的全限定名称,id必须是dao接口中的方法名。
(3)怎么用?代码怎么写?调用sqlSession对象的getMapper方法

AccountDao accountDao = sqlSession.getMapper(AccountDao.class);

 二:面向接口的方式进行CRUD

(1)既然已经学习了面向接口编程和使⽤javassist⽣成类,下面就尝试面向接口的方式进行CRUD操作。

(2)以后重点写映射文件CarMapper.xml和接口CarMapper就可以。

框架结构

(1)pom.xml中引入依赖

jdbc.properties连接数据库的配置文件、mybatis-config.xml核心配置文件、logback日志配置文件都和前面相同,这里就不在列出。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bjpowernode</groupId>
    <artifactId>mybatis-005-crud2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <!--引入依赖-->
    <dependencies>
        <!--mybatis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.10</version>
        </dependency>
        <!--mysql依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.23</version>
        </dependency>
        <!--junit依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--logback依赖-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.11</version>
        </dependency>
    </dependencies>


</project>

(2)接口CarMapper,在这个接口中写抽象方法,下面用动态代理机制生成实现类

package com.bjpowernode.mybatis.mapper;

import com.bjpowernode.mybatis.pojo.Car;

import java.util.*;

public interface CarMapper { // 就相当于CarMapper
    // 增
    int insert(Car car);
    // 删
    int deleteById(Long id);
    // 改
    int update(Car car);
    // 查一个
    Car selectById(Long id);
    // 查所有
    List<Car> selectAll();
}

(3)CarMapper.xml映射文件,编写sql语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.bjpowernode.mybatis.mapper.CarMapper">
    <insert id="insert">
        insert into t_car values(null, #{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    </insert>
    <delete id="deleteById">
         delete from t_car where id = #{id}
    </delete>
    <update id="update">
        update t_car set
        car_num=#{carNum},
        brand=#{brand},
        guide_price=#{guidePrice},
        produce_time=#{produceTime},
        car_type=#{carType}
        where id = #{id}
    </update>
    <select id="selectById" resultType="com.bjpowernode.mybatis.pojo.Car">
        select
            id,
            car_num as carNum,
            brand,
            guide_price as guidePrice,
            produce_time as produceTime,
            car_type as carType
        from t_car where id = #{id}
    </select>
    <select id="selectAll" resultType="com.bjpowernode.mybatis.pojo.Car">
        select
            id,
            car_num as carNum,
            brand,
            guide_price as guidePrice,
            produce_time as produceTime,
            car_type as carType
        from t_car
    </select>
</mapper>

(4)测试类,使用动态代理机制实现CRUD

package com.bjpowernode.mybatis.test;

import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.*;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.mybatis.test
 * @Project:mybatis
 * @name:CarMapperTest
 * @Date:2023/1/3 12:10
 */
public class CarMapperTest {
    @Test
    public  void testInsert(){
        SqlSession sqlSession = SqlSessionUtils.openSession();
        // 面向接口获取接口的代理对象
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(null, "4444", "奔驰C200", 32.0, "2000-10-10", "新能源");
        int count = mapper.insert(car);
        System.out.println(count);
        sqlSession.commit();
    }

    @Test
    public void testDeleteById(){
        SqlSession sqlSession = SqlSessionUtils.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        int count = mapper.deleteById(15L);
        System.out.println(count);
        sqlSession.commit();
    }

    @Test
    public void testUpdate(){
        SqlSession sqlSession = SqlSessionUtils.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(19L, "2222", "凯美瑞222", 3.0, "2000-10-10", "新能源");
        mapper.update(car);
        sqlSession.commit();
    }

    @Test
    public void testSelectById(){
        SqlSession sqlSession = SqlSessionUtils.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(20L);
        System.out.println(car);
    }

    @Test
    public void testSelectAll(){
        SqlSession sqlSession = SqlSessionUtils.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAll();
        for (Car car : cars){
            System.out.println(car);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSH原理与运用

SSH原理与运用 SSH原理与运用&#xff08;一&#xff09;&#xff1a;远程登录 SSH原理与运用&#xff08;二&#xff09;&#xff1a;远程操作与端口转发 一. 什么是SSH&#xff1f; 简单说&#xff0c;SSH是一种网络协议&#xff0c;用于计算机之间的加密登录。需要指出的…

7个流行的强化学习算法及代码实现

目前流行的强化学习算法包括 Q-learning、SARSA、DDPG、A2C、PPO、DQN 和 TRPO。 这些算法已被用于在游戏、机器人和决策制定等各种应用中&#xff0c;并且这些流行的算法还在不断发展和改进&#xff0c;本文我们将对其做一个简单的介绍。 1、Q-learning Q-learning&#xff1…

23种设计模式(十九)——迭代器模式【数据结构】

文章目录 意图什么时候使用迭代器真实世界类比迭代器模式的实现迭代器模式的优缺点亦称:Iterator 意图 提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。 什么时候使用迭代器 1、当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 …

[QMT]05-获取基础行情信息

函数&#xff1a;获取合约基础信息get_instrument_detail(stock_code)1释义获取合约基础信息参数stock_code - string 合约代码返回 dict 数据字典&#xff0c;{ field1 : value1, field2 : value2, ... }&#xff0c;找不到指定合约时返回NoneExchangeID - string 合约市场代码…

零基础学JavaWeb开发(二十)之 spring框架(3)

SpringBean的AOP 1、AOP基本的概念 AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面&#xff0c;即解剖对象的内部&#xff0c;将那些影响了多个类的公共行为抽取到一个可重用模块里&#xff0c;减少系统的重复代码&#xff…

二叉树知识锦囊(三)

作者&#xff1a;爱塔居 专栏&#xff1a;数据结构​​​​​​ 作者简介&#xff1a;大三学生&#xff0c;希望和大家一起进步&#xff01; 目录 前言 1. 检查两棵树是否相同。 2. 另一颗树的子树。 3. 翻转二叉树。 4. 判断一颗二叉树是否是平衡二叉树。 5. 对称二叉树。 前…

【Python】Python数据结构之布尔类型(bool)

目录&#xff1a;Python数据结构之布尔类型&#xff08;bool&#xff09;一、布尔说明二、判定三、布尔运算&#xff1a; and, or, not一、布尔说明 Python 中布尔值使用常量True 和 False来表示&#xff1b;注意大小写。比较运算符< > 等返回的类型就是bool类型&#…

C++虚继承,虚基表 ,菱形继承以及解决方法

目录菱形继承形成原因出现二义性变量的内存布局应对方案虚继承 vitrual解决二义性变量内存布局--虚基表感悟关于代码复用等的另一种关系-组合菱形继承形成原因 多继承&#xff0c;呈菱形状 菱形继承代码: class A { public:A() {}int _a ; }; class B :public A { public…

分享131个ASP源码,总有一款适合您

ASP源码 分享131个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 131个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/17vXlBvqeYPM5-XUlu5zaAg?pwd3zzi 提取码&#x…

【Qt】如何使用QtCreator向工程添加文件

文章目录一、导读二、盘一盘文件模板&#xff08;2-1&#xff09;添加C/C文件&#xff08;2-2&#xff09;添加Modeling文件&#xff08;2-3&#xff09;添加Qt相关文件&#xff08;2-4&#xff09;添加GLSL相关文件&#xff08;2-5&#xff09;添加其他文件三、总结一、导读 …

【JavaSE专栏3】JDK安装、IntelliJ IDEA安装、配置环境变量

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

【苹果相册推】Xcode项目,我们将其命名为mypushchat,以及调试的iOS设备

推荐内容IMESSGAE相关 作者✈️IMEAX推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容3.日历推 *** …

第二个程序——客户端ClientUI

简介 在我的上一篇文章中&#xff0c;我已经介绍了如何实现“在线聊天室”中的服务器端ServerUI&#xff0c;服务器端作为整个聊天系统的“中继系统”&#xff0c;负责转发用户的信息到聊天室&#xff0c;可以转发给聊天室中的每一个人&#xff08;即&#xff0c;群聊&#xf…

一期Go群问答-并发控制-数据竞争-错误与异常

每周更新Go技术交流群的群问答内容&#xff0c;有需要可发我Go加群讨论学习。 并发控制 waitGroup.done()不是必须写在main方法中吗? 为什么我的协程没有成功等待&#xff1f; 熊&#xff1a;如果用了wait group&#xff0c;请求就直接卡住了&#xff0c;如果只有一个gorou…

Linux C编程一站式学习笔记5

Linux C编程一站式学习笔记 chap5 深入理解函数 文章目录Linux C编程一站式学习笔记 chap5 深入理解函数一.return语句习题二.增量式开发三.递归我猜有递归可视化工具&#xff0c;一搜果真有收获习题GCD(Greatest Common Divisor) 最大公约数Fibonacci相关资源、参考资料嘶&…

在linux中安排mysql

linux安装mysql 检测当前系统中是否安装Mysql数据库 rpm -qa rpm -qa|grep mysql rpm -qa|grep mariadb没有输出就是没有安装 我的这里显示mariadb是安装了的&#xff08;会与mysql冲突&#xff09; 卸载已经安装的软件 rpm -e --nodeps 软件名称 rpm -e --nodeps mariadb-li…

什么是执行董事

一、什么是执行董事执行董事&#xff0c;是指参与经营的董事。作为法定意义上的执行董事&#xff0c;是指规模较小的有限公司在不设立董事会的情况下设立的负责公司经营管理的职务。作为上市公司意义上的执行董事&#xff0c;执行董事并没有明确的法规依据。执行董事和非执行董…

偷偷理解Java和Scala中==和equals()的区别

君霸王&#xff0c;社稷定&#xff0c;君不霸王&#xff0c;社稷不定&#x1f97d; 目录 Java总结 Scala总结 Java中和equals() ---------------------------------------------------------------------------------------------------------------------------------------…

【人工智能原理自学】卷积神经网络:图像识别实战

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文讲解卷积神经网络&#xff1a;图像识别实战&#xff0c;一起卷起来叭&#xff01; 目录一、“卷”二、LeNet-5网络一、“卷” 这节课我们来看如何把卷积运算融入到神经网络…

【青训营】Go语言的基本语法

一、 配置Go语言及其开发环境 Mac配置&#xff1a;http://t.zoukankan.com/zsy-p-6685889.html https://wenku.baidu.com/view/8aeec92b15fc700abb68a98271fe910ef12daeaf.html?wkts1673764660043&bdQuery%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AEgopathmac 二、基础语法 p…