框架-Spring

一、Spring框架概述

1、Spring是轻量级的开源的javaEE框架。

2、Spring可以解决企业应用开发的复杂性。

3、Spring的核心:IOC,AOP

  • IOC:控制反转(Inversion of Control),把创建对象的过程交给Spring容器进行管理
  • AOP:面向切面,不修改源代码进行功能增强

4、Spring特点

  • 方便解耦,简化开发
  • AOP编程支持
  • 方便程序测试(junit)
  • 方便和其他框架进行整合(mybatis)
  • 降低API开发难度
  • 方便进行事务操作

二、入门案例

Spring架构图

ioc基本包下载

IOC基本包有这5个:

Spring官网版本说明

  • GA表示稳定版本 ,选这个

  • SNAPSHOT表示快照版本

Spring历史版本下载

1
2
3
4
5
6
7
8
#spring下载好后的目录架构
.
├── docs #API文档和开发规范
├── libs #开发需要的JAR包和源码
├── license.txt
├── notice.txt
├── readme.txt
└── schema #开发所需要的schema文件

第一个是项目需要导入的jar包,javadoc是帮助文档,sources是源码文件

commons-logging包下载

将jar包导入项目中

测试

文件结构:

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestDemo {
@Test
public void test01(){
//加载spring配置文件
//类路径classpath就是在src目录下
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

//获取容器配置好的bean对象
User user1 = context.getBean("user1", User.class);

System.out.println(user1);
user1.add();
}
}

三、Spring IOC

Spring 提供 IOC 容器两种实现方式:(两个接口)

  • BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用 ,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
  • ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件对象进行创建,ApplicationContext 接口有实现类

Bean管理

  1. Spring创建对象

  2. Spring注入属性

Bean类型

1、普通bean

2、工厂bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//基础类
public class Course {
private String cname;
private int cid;

public void setCname(String cname) {
this.cname = cname;
}

public void setCid(int cid) {
this.cid = cid;
}

@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
", cid=" + cid +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//工厂!!!
public class MyBean implements FactoryBean<Course> {

@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("哈哈");
return course;
}

@Override
public Class<?> getObjectType() {
return Course.class;
}

@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
1
2
//配置文件
<bean id="myBean" class="spring5.vickkkyz.Factory.MyBean"></bean>
1
2
3
4
5
6
7
//测试类!!!在配置文件中定义bean类型可以和返回类型不同
@Test
public void test04(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Course myBean = context.getBean("myBean", Course.class);
System.out.println(myBean);
}

Bean作用域

在Spring中创建的bean默认是单实例的

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestDemo {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user1 = context.getBean("user1",User.class);
User user2 = context.getBean("user1",User.class);
System.out.println(user1);
System.out.println(user2);
}
}

//spring5.vickkkyz.User@49b0b76
//spring5.vickkkyz.User@49b0b76

可以在配置文件中设置这个bean是单实例的还是多实例的

scope 属性值

  • singleton,默认值,表示是单实例对象
  • prototype,表示是多实例对象
1
<bean id="user1" class="spring5.vickkkyz.User" scope="prototype"></bean>
1
2
//spring5.vickkkyz.User@769f71a9
//spring5.vickkkyz.User@4c9f8c13
  • 设置 scope 为 singleton 的时候,在加载 Spring 配置文件时候就会创建单实例对象
  • 如果 scope 为 prototype 的时候,不是在加载 Spring 配置文件的时候创建对象,而是在调用 getBean 方法的时候创建多实例对象

Bean的生命周期

  • 生命周期:从对象的创建到对象的销毁的过程。

  • 过程:

    (1)通过无参构造器创建bean实例

    (2)通过set方法为bean的属性设置值和对其他bean的引用赋值

    (3)调用bean的初始化方法

    (4)bean可以使用了

    (5)当容器关闭时,调用bean的销毁方法

想自己看整个流程需要在xml配置文件的bean配置中指定初始化和销毁方法

1
<bean id="user1" class="spring5.vickkkyz.User" init-method="" destory-method=""></bean>

销毁的话需要在test测试类中context.close()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//基础类、、、、、
public class book {
private String name;
private int num;

public book(){
System.out.println("无参构造器....");
}

public void setName(String name) {
this.name = name;
}

public void setNum(int num) {
this.num = num;
}

@Override
public String toString() {
return "book{" +
"name='" + name + '\'' +
", num=" + num +
'}';
}

public void initMethod(){
System.out.println("初始化构造方法....");
}

public void destoryMethod(){
System.out.println("销毁方法....");
}
}
1
2
3
4
<bean id="book1" class="spring5.vickkkyz.Book.book" init-method="initMethod" destroy-method="destoryMethod">
<property name="name" value="童年"></property>
<property name="num" value="1"></property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void test05(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
book book1 = context.getBean("book1", book.class);
System.out.println(book1);
context.close();
}

//结果:
//无参构造器....
//执行set方法赋值
//(如果有后置处理器)初始化前,执行后置处理器的before方法
//初始化构造方法....
//(如果有后置处理器)初始化后,执行后置处理器的after方法
//book{name='童年', num=1}
//销毁方法....

后置处理器的实现:定义一个类,实现BeanPostProcesser接口,重写before和after方法,在spring配置文件中配置后置处理器

Bean管理操作的方式

1、基于xml配置文件方式

(1)创建对象

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="user1" class="spring5.vickkkyz.User"></bean>

</beans>

在spring配置文件中,使用bean标签,标签里添加对应的属性,就可以实现spring帮我们进行对象创建。

bean标签中的属性:

  • id:给对象起一个标识名字(唯一)
  • class:类的全路径

创建对象时是利用类的无参构造方法。

(2)注入属性

​ DI:依赖注入,即注入属性。

第一种注入方式:使用set方法进行注入

1
2
3
4
5
6
7
8
9
10
11
12
public class User {
private String bname;
private int bage;

public void setBage(int age) {
this.bage = age;
}

public void setBname(String name) {
this.bname = name;
}
}
1
2
3
4
5
6
7
8
<bean id="user1" class="spring5.vickkkyz.User">
<!--使用property属性完成注入
name的值为类里面属性的名称
value为要注入的值
-->
<property name="bname" value="小明"></property>
<property name="bage" value="12"></property>
</bean>

第二种注入方法:使用有参构造器进行注入

1
2
3
4
5
6
7
8
9
public class Orders {
private String name;
private String address;

public Orders(String name, String address) {
this.name = name;
this.address = address;
}
}
1
2
3
4
<bean id="order" class="spring5.vickkkyz.Orders">
<constructor-arg name="name" value="小张"></constructor-arg>
<constructor-arg name="address" value="China"></constructor-arg>
</bean>

第三种注入方式:p名称空间注入(可以说是set方法注入的简化版)

增加这个xmlns:p="http://www.springframework.org/schema/p"

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="user1" class="spring5.vickkkyz.User" scope="prototype" p:bname="你好" p:bage="12"></bean>

</beans>

给属性注入的值的类型

  1. 属性的类型是String或者基本数据类型 null

    1
    2
    3
    <property name="bname" >
    <null/>
    </property>
  2. 属性的类型是String或基本数据类型 特殊符号(< >)

    1
    2
    3
    4
    5
    6
    7
    <property name="bname" >
    <value>
    <![CDATA[<<南京>>]]>
    </value>
    </property>

    <!-- 输出 <<南京>> -->
  3. 属性是引用数据类型(对象) 注入外部bean

    外部bean:直接在beans标签内部直接定义的bean对象,外部bean可以被多个bean对象引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class userService {
    private spring5.vickkkyz.Dao.userDao userDao;

    public void setUserDao(spring5.vickkkyz.Dao.userDao userDao) {
    this.userDao = userDao;
    }

    public void add(){
    System.out.println("userService.....");
    userDao.add();
    }
    }
    1
    2
    3
    4
    5
    public class userDao {
    public void add(){
    System.out.println("userDao.....");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="service" class="spring5.vickkkyz.Service.userService">
    <property name="userDao" ref="dao"></property>
    </bean>

    <bean id="dao" class="spring5.vickkkyz.Dao.userDao"></bean>
    </beans>


    <!-- 这样写就是级联赋值了

    <bean id="service" class="spring5.vickkkyz.Service.userService">
    <property name="userDao" ref="dao"></property>
    </bean>

    <bean id="dao" class="spring5.vickkkyz.Dao.userDao">
    <property name="name" value="这是内部bean的案例"></property>
    </bean>

    -->

    <!--
    <bean id="service" class="spring5.vickkkyz.Service.userService">
    <property name="userDao" ref="dao"></property>
    <property name="userDao.name" value="这是内部bean的案例"></property> //写这个需要写get方法
    </bean>

    <bean id="dao" class="spring5.vickkkyz.Dao.userDao">

    </bean>

    -->
  4. 属性是引用数据类型(对象) 注入内部bean

    内部bean:在某个bean标签的内部定义的bean对象,内部bean只能被某个对象的某个属性引用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="service" class="spring5.vickkkyz.Service.userService">
    <property name="userDao">
    <bean id="dao" class="spring5.vickkkyz.Dao.userDao">
    <property name="name" value="这是内部bean的案例"></property>
    </bean>
    </property>
    </bean>

    </beans>
  5. 属性是数组类型、List类型、Map集合类型 注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class student {
    private String[] courses;
    private List<String> list;
    private Map<String,String> map;

    public void setCourses(String[] courses) {
    this.courses = courses;
    }

    public void setList(List<String> list) {
    this.list = list;
    }

    public void setMap(Map<String, String> map) {
    this.map = map;
    }

    @Override
    public String toString() {
    return "student{" +
    "courses=" + Arrays.toString(courses) +
    ", list=" + list +
    ", map=" + map +
    '}';
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <bean id="student" class="spring5.vickkkyz.Collection.student">
    <property name="courses">
    <array>
    <value>数组第一个元素</value>
    <value>数组第二个元素</value>
    </array>
    </property>

    <property name="list">
    <list>
    <value>集合第一个元素</value>
    <value>集合第二个元素</value>
    </list>
    </property>

    <property name="map">
    <map>
    <entry key="key1" value="value1"></entry>
    <entry key="key2" value="value2"></entry>
    </map>
    </property>

    </bean>

    list元素是对象的情况下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class Course {
    private String cname;
    private int cid;

    public void setCname(String cname) {
    this.cname = cname;
    }

    public void setCid(int cid) {
    this.cid = cid;
    }

    @Override
    public String toString() {
    return "Course{" +
    "cname='" + cname + '\'' +
    ", cid=" + cid +
    '}';
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="spring5.vickkkyz.Collection.student">
    <property name="list">
    <list>
    <ref bean="course1"></ref>
    <ref bean="course2"></ref>
    </list>
    </property>

    </bean>

    <bean id="course1" class="spring5.vickkkyz.Collection.Course">
    <property name="cname" value="数学"></property>
    <property name="cid" value="1"></property>
    </bean>

    <bean id="course2" class="spring5.vickkkyz.Collection.Course">
    <property name="cname" value="英语"></property>
    <property name="cid" value="2"></property>
    </bean>
    </beans>

    将集合注入部分抽取成公共部分

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-beans.xsd">

    <util:list id="courselist">
    <!-- 基本数据类型和String类型就直接用value标签来赋值-->
    <!-- <value></value>-->
    </util:list>

    <bean id="student" class="spring5.vickkkyz.Collection.student">
    <property name="list" ref="courselist"></property>
    </bean>

    </beans>

    自动装配

    上面所有用的方式都是手动装配,即手动给类中的属性设置值。

    只有非字面量(非基本数据类型及其封装类)的属性才能自动装配

    比如现在有两个类A,B。在类A中有一个属性类B,在spring配置文件中配置类A,对于类A的属性B不需要手动配置,而是在bean标签内有一个atuowire标签 自动装配。(需要提前配置好类B)

    自动装配类型:

    • byName 注入值 bean 的 id 值和在类A中B的属性名称一样
    • byType 根据属性类型注入

2、基于注解方式

注解的格式:@注解名称(属性名称=属性值,属性名称=属性值..)

注解是为了简化xml的配置

第一步:引入依赖包

commons-logging-1.2.jar
spring-aop-5.3.21.jar
spring-beans-5.3.21.jar
spring-context-5.3.21.jar
spring-core-5.3.21.jar
spring-expression-5.3.21.jar

第二步:开启组件扫描

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- base-package 表示扫描哪个包-->
<context:component-scan base-package="spring5.vickkkyz"></context:component-scan>

</beans>

自定义扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--
默认的filter 扫描base-package下指定包路径下的所有注解(4个)
use-default-filters="false" 表示不使用默认的filter,自己配置
context:include-filter表示只扫描spring5.vickkkyz包下的expression所指示的注解
exclude就是排除出去,不扫描
-->
<context:component-scan base-package="spring5.vickkkyz" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

</beans>

第三步:使用注解

1类相关的注解: Spring中针对bean管理中创建对象提供的注解有:

@Component

@Service

@Controller

@Repository

2 属性相关的注解

@Atuowired 按照类型(class)进行自动装配

@Qualifier 按照名称进行自动装配,需要和Autowired一起使用

@Resource 可以按照类型,也可以按照名称

@Value 对String类型的自动装配

1
2
3
4
5
@Resource(name = "userDao")
private UserDao userDao;

@Value(value = "ad")
private String hello;

完全注解模式:不用xml文件

使用配置类代替xml文件

1
2
3
4
5
@Configuration //作为配置类,替代xml文件
@ComponentScan(basePackages = {"spring5.vickkkyz"})
public class SpringConfig {

}

测试类:

1
2
3
4
5
6
@Test
public void test01(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}

四、Spring AOP

AOP相关概念

面向切面编程,基于OOP面向对象编程,底层就是AOP在程序运行期间,将某段代码(日志代码)动态地切入(不把日志代码写死在业务逻辑方法中)到指定方法的指定位置(方法的开始,结束,异常等位置)进行运行的这种编程方式。

jdk默认的动态代理:如果目标对象没有实现任何借口,是无法为他创建代理对象的,因为jdk动态代理与目标对象就是靠实现同一个接口来建立的。

利用Spring AOP的优点:实现简单,没有强制要求目标对象必须实现接口

AOP使用步骤

1、导包

Spring基础包

commons-logging-1.2.jar
spring-aop-5.3.21.jar
spring-beans-5.3.21.jar
spring-context-5.3.21.jar
spring-core-5.3.21.jar
spring-expression-5.3.21.jar

AOP相关的包

spring-aop-5.3.21.jar

com.springsource.net.sf.cglib-2.2.0.jar

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

2、写配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--开启包扫描-->
<context:component-scan base-package="spring5.vickkkyz"></context:component-scan>

<!--开启基于注解的aop功能-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

myCalculator实现接口的情况下:

1
2
3
4
5
6
public interface Calculator {
int add(int a,int b);
int delete(int a,int b);
int cheng(int a,int b);
int chu(int a,int b);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class MyCalculator implements Calculator{
@Override
public int add(int a, int b) {
return a+b;
}

@Override
public int delete(int a, int b) {
return a-b;
}

@Override
public int cheng(int a, int b) {
return a*b;
}

@Override
public int chu(int a, int b) {
return a/b;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Aspect
@Component
public class LogUtil {

/**
* @Before 在目标方法之前运行
* @After 在目标方法结束之后
* @AfterReturning 在目标方法正常返回之后
* @AfterThrowing 在目标方法抛出异常之后执行
* @Around 环绕通知,是上面4个通知的结合
*/

//切入点表达式的固定格式:execution(访问权限符 返回值类型 方法全类名(参数表))
@Before("execution(public int spring5.vickkkyz.jisuanqi.MyCalculator.*(int,int))")
public static void logStart(){
System.out.println("方法开始前。。。");
}
@AfterReturning("execution(public int spring5.vickkkyz.jisuanqi.MyCalculator.*(int,int))")
public static void logReturn(){
System.out.println("方法正常返回后。。。");
}
@AfterThrowing("execution(public int spring5.vickkkyz.jisuanqi.MyCalculator.*(int,int))")
public static void logExecption(){
System.out.println("方法抛出异常后。。。");
}

@After("execution(public int spring5.vickkkyz.jisuanqi.MyCalculator.*(int,int))")
public static void logEnd(){
System.out.println("方法最终结束后。。。");
}


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TestDemo {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//注意是接口类型才行,因为是动态代理
//容器中保存的组件是MyCalculator的代理对象Proxy
Calculator myCalculator = context.getBean("myCalculator", Calculator.class);
myCalculator.add(1,0);

//spring5.vickkkyz.jisuanqi.MyCalculator@183ec003
//class com.sun.proxy.$Proxy19
System.out.println(myCalculator);
System.out.println(myCalculator.getClass());
}
}

myCalculator没有实现接口的情况下:

由cglib来创建动态代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestDemo {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//注意是接口类型才行,因为有动态代理
MyCalculator myCalculator = context.getBean("myCalculator", MyCalculator.class);
myCalculator.add(1,0);
//spring5.vickkkyz.jisuanqi.MyCalculator@638ef7ed
//class spring5.vickkkyz.jisuanqi.MyCalculator$$EnhancerBySpringCGLIB$$642353d5
System.out.println(myCalculator);
System.out.println(myCalculator.getClass());
}
}

3、测试


JdbcTemplate是Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作

四、参考

本文参考:简简的博客尚硅谷


框架-Spring
https://vickkkyz.fun/2022/07/02/Java/framework/Spring/
作者
Vickkkyz
发布于
2022年7月2日
许可协议