Spring
SPRING概述
Spring是一个开源的Java框架,它提供了一种轻量级的、非侵入式的开发方式,用于构建企业级应用程序和服务。Spring的目标是简化Java应用程序的开发,并提供一种灵活的编程模型。
Spring框架的核心特点包括:
-
IoC容器(Inversion of Control,控制反转):IoC是Spring框架的核心概念之一,它通过将对象的创建和管理工作交给Spring容器来实现,开发人员只需声明对象的依赖关系,而不需要显式地创建和管理对象。这种解耦方式可以降低组件之间的耦合性,提高代码的可重用性和可测试性。
-
依赖注入(Dependency Injection,DI):依赖注入是IoC的一种实现方式,它通过将依赖对象注入到需要它的对象中,解决了对象之间的依赖关系。Spring框架通过注解或配置文件的方式实现依赖注入,使得对象之间的关系更加清晰和可配置。
-
面向切面编程(Aspect-Oriented Programming,AOP):AOP是一种编程范式,它可以将横切关注点(如日志记录、事务管理等)从主要业务逻辑中分离出来,提高了代码的模块化和可维护性。Spring框架提供了AOP的支持,开发人员可以使用切面来定义和管理横切关注点。
-
Spring MVC:Spring MVC是Spring框架的一个模块,用于开发基于MVC(Model-View-Controller)模式的Web应用程序。它提供了一套灵活的Web开发框架,支持处理HTTP请求、路由、视图渲染等功能。
-
集成其他框架和技术:Spring框架可以与其他框架和技术(如Hibernate、MyBatis、JPA等)无缝集成,提供了丰富的API和配置选项,使得开发人员可以根据需求选择适合的组件和工具。
总的来说,Spring框架通过提供IoC容器、依赖注入、AOP和Web开发支持等功能,简化了Java应用程序的开发过程,并促进了代码的可维护性、可测试性和扩展性。它已经成为企业级Java应用程序开发的主流框架之一。
IOC容器
IOC概念
IOC(Inversion of Control,控制反转)容器是Spring框架的核心组件之一,它负责管理和组织应用程序中的对象(也称为Bean)。IOC容器通过控制对象的创建、配置和生命周期管理,将这些职责从应用程序代码中解耦出来。
在传统的开发模式中,开发人员通常需要手动创建和管理对象的依赖关系。但是在Spring框架中,IOC容器将这项工作交给了自己来完成。开发人员只需声明对象之间的依赖关系,而无需显式地创建和管理对象。
IOC容器的主要作用有:
-
对象的创建和管理:IOC容器负责创建对象实例,并管理它们的生命周期。开发人员只需声明对象的依赖关系,容器会负责根据配置信息实例化相应的对象。
-
依赖注入:IOC容器通过依赖注入(Dependency Injection,DI)将依赖对象注入到需要它的对象中。依赖注入可以通过构造函数、Setter方法或字段注入的方式实现。开发人员只需定义依赖关系,容器会负责将依赖对象注入到相应的位置。
-
对象的配置管理:IOC容器提供了灵活的配置方式,可以使用XML配置文件、注解或Java代码来描述对象的创建和依赖关系。通过配置管理,可以实现对象的灵活组装和切换,使得系统的配置更加可扩展和可配置。
-
AOP集成:IOC容器与面向切面编程(AOP)密切相关。容器可以通过AOP的方式在对象的创建和管理过程中插入横切关注点,实现诸如事务管理、日志记录、安全性检查等通用功能。
在Spring框架中,有多个IOC容器的实现可供选择,其中最常用的是ApplicationContext。ApplicationContext是BeanFactory接口的一个实现,它提供了更多的功能和扩展,如国际化支持、事件发布、Web应用程序的特殊集成等。
通过使用IOC容器,开发人员可以实现解耦、可测试和可扩展的应用程序,提高代码的可维护性和可重用性。
IOC底层原理
- xml解析、工厂模式、反射
IOC(接口)
-
IOC的思想基于IOC容器完成,IOC底层本质上就是对象工厂;
-
Spring提供IOC容器实现的两种方式;(两个接口)
- BeanFactory:IOC容器的基本实现,是Spring内部的使用接口,不提供开发人员进行使用。加载配置文件时不会创建对象,在获取对象才会创建对象。
- ApplicationContext:BeanFactory的子接口,提供更多强大的功能,一般由开发人员使用。加载配置文件时就会把在配置文件对象进行创建。
-
ApplicationContext接口实现类
在Spring框架中,有多个ApplicationContext的实现类可供选择,每个实现类都针对不同的使用场景和环境提供了特定的功能和扩展。以下是几个常用的ApplicationContext实现类:
-
ClassPathXmlApplicationContext:ClassPathXmlApplicationContext是从类路径下的XML配置文件加载ApplicationContext的实现类。它会在类路径下查找并加载指定的XML配置文件,根据配置文件中的定义创建和管理对象。这是最常用的ApplicationContext实现类之一。
-
FileSystemXmlApplicationContext:FileSystemXmlApplicationContext是从文件系统中的XML配置文件加载ApplicationContext的实现类。它可以根据文件系统路径加载XML配置文件,并创建和管理对象。相比于ClassPathXmlApplicationContext,它更适合于在开发过程中指定具体的文件路径。
-
XmlWebApplicationContext:XmlWebApplicationContext是在Web应用程序环境中使用的ApplicationContext实现类。它可以从Web应用程序的配置文件中加载ApplicationContext,提供了对Web特定功能的支持,如处理Servlet、监听器和过滤器等。
-
AnnotationConfigApplicationContext:AnnotationConfigApplicationContext是基于Java配置的ApplicationContext实现类。它不使用XML配置文件,而是通过注解和Java类来定义Bean和配置信息。开发人员可以使用@Configuration和@Bean等注解来声明配置类和Bean定义,从而实现ApplicationContext的创建和管理。
除了上述常用的实现类,Spring还提供了其他一些特定场景下的ApplicationContext实现类,如:
-
StaticApplicationContext:用于在静态环境下创建和管理ApplicationContext的实现类,适用于一些非常特殊的使用场景。
-
AnnotationConfigWebApplicationContext:用于在Web应用程序中使用基于注解的配置的ApplicationContext实现类,结合了XmlWebApplicationContext和AnnotationConfigApplicationContext的功能。
这些ApplicationContext的实现类提供了不同的加载和配置方式,可以根据具体的需求选择合适的实现类来创建和管理Spring的ApplicationContext容器。
-
IOC操作Bean管理
1.什么是Bean管理
- Bean管理指的是两个操作;
- Spring 创建对象;
- Spring 注入属性。
2.Bean管理操作有两种方式
- 基于xml配置文件方式实现;
- 基于注解方式实现;
3.IOC操作Bean管理(基于xml方式)
(1)基于xml方式创建对象
<bean id="dao" class="com.kgh.demo.dao.book"></bean>
-
在spring配置文件中,使用bean标签,标签里面添加对应的属性,就可以实现对象的创建;
-
在bean标签有很多属性,介绍常用的属性;
- id属性:唯一标识
- name属性:类全路径
-
创建对象时候,默认也是执行无参构造方法完成对象创建。
(2)基于xml方式注入属性
-
DI:依赖注入,就是注入属性;
(3)第一种注入方式,set方法注入
使用set方法原始方法注入
public class book { private String bname; private String bauthor; public void setBname(String bname) { this.bname = bname; } public void setBauthor(String bauthor) { this.bauthor = bauthor; } public static void main(String[] args) { book book = new book(); book.setBauthor("罗贯中"); book.setBname("三国演义"); } }
在spring配置文件配置对象创建,配置属性注入
<bean id="dao" class="com.kgh.demo.dao.book"> <property name="bname" value="三国演义"/> <property name="bauthor" value="罗贯中"/> </bean>
(4)第二种注入方式,使用有参构造进行注入
索引方式注入
<bean id="dao" class="com.kgh.demo.dao.book"> <constructor-arg index="0" value="三国演义"/> <constructor-arg index="1" value="罗贯中"/> </bean>
name属性注入
<bean id="dao" class="com.kgh.demo.dao.book"> <constructor-arg name="bname" value="三国演义"/> <constructor-arg name="bauthor" value="罗贯中"/> </bean>
4.IOC操作Bean管理(xml注入其他类型属性)
(1)注入空值和特殊符号
null值
<bean id="dao" class="com.kgh.demo.dao.book">
<property name="address">
<null></null>
</property>
</bean>
属性包含特殊符号
<bean id="dao" class="com.kgh.demo.dao.book">
<property name="address">
<value><![CDATA[<<南京>>]]>></value>
</property>
</bean>
(2)注入属性-外部Bean
<bean id="userdao" class="com.kgh.demo.dao.UserdaoImpl"/>
<bean id="userservice" class="com.kgh.demo.service.UserService">
<property name="dao" ref="userdao"/>
</bean>
(3)注入属性-内部bean
<bean id="user" class="com.kgh.demo.bean.Emp">
<property name="name" value="kgh"/>
<property name="gender" value="man"/>
<property name="dept">
<bean id="dept" class="com.kgh.demo.bean.Dept">
<property name="dname" value="组织部"/>
</bean>
</property>
</bean>
(4)注入属性-级联赋值
<bean id="user" class="com.kgh.demo.bean.Emp">
<property name="name" value="kgh"/>
<property name="gender" value="man"/>
<property name="dept" ref="dept"/>
</bean>
<bean id="dept" class="com.kgh.demo.bean.Dept">
<property name="dname" value="财务部"/>
</bean>
5.IOC操作Bean管理(xml注入集合类型属性)
(1)注入数组类型的属性
<bean id="arr" class="com.kgh.controller.Stu">
<property name="courses">
<array>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
</bean>
(2)注入List集合类型的属性
<bean id="arr" class="com.kgh.controller.Stu">
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
</bean>
(3)注入Map集合类型的属性
<bean id="arr" class="com.kgh.controller.Stu">
<property name="maps">
<map>
<entry key="kgh" value="美男子"/>
</map>
</property>
</bean>
(4)在集合里面设置对象类型值
<bean id="arr" class="com.kgh.controller.Stu">
<property name="courseList">
<list>
<ref bean="course"/>
<ref bean="course2"/>
</list>
</property>
</bean>
<!-- 配置多个course对象-->
<bean id="course" class="com.kgh.controller.Course">
<property name="name" value="计算机课程"/>
</bean>
<bean id="course2" class="com.kgh.controller.Course">
<property name="name" value="高等数学"/>
</bean>
</beans>
6. IOC 操作 Bean 管理(FactoryBean)
Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
普通 bean:在配置文件中定义 bean 类型就是返回类型
工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
public class MyBean implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("abc");
return course;
}
}
<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean">
</bean>
@Test
public void test3() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean3.xml");
Course course = context.getBean("myBean", Course.class);//返回值类型可以不是定义的bean类型!
System.out.println(course);
}
7.IOC 操作 Bean 管理(bean 作用域)
在 Spring 里面,默认情况下,bean 是单实例对象,下面进行作用域设置:
(1)在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
(2)scope 属性值 第一个值 默认值,singleton,表示是单实例对象 第二个值 prototype,表示是多实例对象
<bean id="book" class="com.atguigu.spring5.collectiontype.Book" scope="prototype"><!--设置为多实例-->
<property name="list" ref="bookList"></property>
</bean>
(3)singleton 和 prototype 区别
- singleton 单实例,prototype 多实例
- 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象 ;设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建对象,在调用 getBean 方法时候创建多实例对象
8.IOC 操作 Bean 管理(bean 生命周期)
1、生命周期 :从对象创建到对象销毁的过程
2、bean 生命周期
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(4)bean 可以使用了(对象获取到了)
(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
3、演示 bean 生命周期 :
public class Orders {
//无参数构造
public Orders() {
System.out.println("第一步 执行无参数构造创建 bean 实例");
}
private String oname;
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用 set 方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步 执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第五步 执行销毁的方法");
}
}
public class MyBeanPost implements BeanPostProcessor {//创建后置处理器实现类
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
}
<!--配置文件的bean参数配置-->
<bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"> <!--配置初始化方法和销毁方法-->
<property name="oname" value="手机"></property><!--这里就是通过set方式(注入属性)赋值-->
</bean>
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
@Test
public void testBean3() {
// ApplicationContext context =
// new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步 获取创建 bean 实例对象");
System.out.println(orders);
//手动让 bean 实例销毁
context.close();
}
4、bean 的后置处理器,bean 生命周期有七步 (正常生命周期为五步,而配置后置处理器后为七步)
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
(6)bean 可以使用了(对象获取到了)
(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
9.IOC 操作 Bean 管理(外部属性文件)
方式一:直接配置数据库信息 :(1)配置Druid(德鲁伊)连接池 (2)引入Druid(德鲁伊)连接池依赖 jar 包
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
方式二:引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties 格式文件,写数据库信息(jdbc.properties)
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=root
(2)把外部 properties 属性文件引入到 spring 配置文件中 —— 引入 context 名称空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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"><!--引入context名称空间-->
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
</beans>
IOC容器 Bean 管理(基于注解方式)
- 什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化 xml 配置
- Spring 针对 Bean 管理中创建对象提供注解
下面四个注解功能是一样的,都可以用来创建 bean 实例
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
- 基于注解方式实现对象创建
第一步 引入依赖 (引入spring-aop jar包)
第二步 开启组件扫描
<!--开启组件扫描
1 如果扫描多个包,多个包使用逗号隔开
2 扫描包上层目录
-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
第三步 创建类,在类上面添加创建对象注解
//在注解里面 value 属性值可以省略不写,
//默认值是类名称,首字母小写
//UserService -- userService
@Component(value = "userService") //注解等同于XML配置文件:<bean id="userService" class=".."/>
public class UserService {
public void add() {
System.out.println("service add.......");
}
}
- 开启组件扫描细节配置
<!--示例 1
use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter
context:include-filter ,设置扫描哪些内容
-->
<context:component-scan base-package="com.atguigu" use-defaultfilters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/><!--代表只扫描Controller注解的类-->
</context:component-scan>
<!--示例 2
下面配置扫描包所有内容
context:exclude-filter: 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/><!--表示Controller注解的类之外一切都进行扫描-->
</context:component-scan>
- 基于注解方式实现属性注入
(1)@Autowired:根据属性类型进行自动装配
第一步 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解
第二步 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解
@Service
public class UserService {
//定义 dao 类型属性
//不需要添加 set 方法
//添加注入属性注解
@Autowired
private UserDao userDao;
public void add() {
System.out.println("service add.......");
userDao.add();
}
}
//Dao实现类
@Repository
//@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("dao add.....");
}
}
(2)@Qualifier:根据名称进行注入,这个@Qualifier 注解的使用,和上面@Autowired 一起使用
//定义 dao 类型属性
//不需要添加 set 方法
//添加注入属性注解
@Autowired //根据类型进行注入
//根据名称进行注入(目的在于区别同一接口下有多个实现类,根据类型就无法选择,从而出错!)
@Qualifier(value = "userDaoImpl1")
private UserDao userDao;
(3)@Resource:可以根据类型注入,也可以根据名称注入(它属于javax包下的注解,不推荐使用!)
//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
(4)@Value:注入普通类型属性
@Value(value = "abc")
private String name
- 完全注解开发
(1)创建配置类,替代 xml 配置文件
@Configuration //作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
}
(2)编写测试类
@Test
public void testService2() {
//加载配置类
ApplicationContext context
= new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService",
UserService.class);
System.out.println(userService);
userService.add();
}
AOP
1、AOP概念
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在解决在应用程序中散布的横切关注点(Cross-cutting Concerns)的问题。横切关注点是那些不属于核心业务逻辑但在多个组件中存在的功能,例如日志记录、事务管理、安全性检查等。
AOP通过将横切关注点从主要业务逻辑中分离出来,提高了代码的模块化和可维护性。它通过定义切面(Aspect)来实现这一目标,切面可以独立地描述横切关注点,并将其应用到需要的组件中。
在AOP中,有几个核心概念:
-
切面(Aspect):切面是横切关注点的模块化单元,它包含了横切关注点的定义和逻辑。切面可以通过配置或编程的方式定义,并指定在哪些连接点(Join Point)上应用。
-
连接点(Join Point):连接点是在应用程序中可以插入切面的特定位置,例如方法的执行、异常抛出或字段的访问等。连接点是AOP中的可执行点,切面可以通过将其与特定的连接点关联来应用到相应的位置。
-
通知(Advice):通知是切面在连接点上执行的动作。在AOP中,有几种类型的通知,包括前置通知(Before Advice)、后置通知(After Advice)、异常通知(After Throwing Advice)、返回通知(After Returning Advice)和环绕通知(Around Advice)等。
-
切点(Pointcut):切点是一组连接点的集合,它定义了在哪些连接点上应用切面。切点可以使用表达式或模式来描述连接点的选择条件,以便精确地定位需要应用切面的位置。
-
增强(Introduction):增强是在不修改原始类的情况下,为类添加新的方法或属性。通过增强,切面可以为目标对象引入新的功能。
Spring框架提供了强大的AOP支持,可以与IOC容器无缝集成。开发人员可以使用注解或XML配置来定义切面和通知,并通过在Spring容器中配置AOP代理,实现切面的自动织入。
使用AOP,开发人员可以将横切关注点独立于核心业务逻辑进行管理,提高了代码的可重用性和可维护性。同时,AOP也使得系统的关注点更加清晰,易于理解和扩展。
实例:
2、AOP底层原理
a)AOP 底层使用动态代理 ,动态代理有两种情况:
第一种 有接口情况,使用 JDK 动态代理 ;创建接口实现类代理对象,增强类的方法
第二种 没有接口情况,使用 CGLIB 动态代理;创建子类的代理对象,增强类的方法
3、AOP(JDK 动态代理)
1)使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象
调用 newProxyInstance 方法,方法有三个参数:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
第一参数,类加载器
第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分
2)编写 JDK 动态代理代码
//(1)创建接口,定义方法
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
//(2)创建接口实现类,实现方法
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
//(3)使用 Proxy 类创建接口代理对象
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类代理对象
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
/** 第一参数,类加载器
第二参数,增强方法所在的类,这个类实现的接口,(支持多个接口)
第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分 */
UserDao dao =(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,
new UserDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println("result:"+result);
}
}
//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
//1 把创建的是谁的代理对象,把谁传递过来
//有参数构造传递
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args));
//被增强的方法执行
Object res = method.invoke(obj, args);
//方法之后
System.out.println("方法之后执行...."+obj);
return res;
}
}
4、AOP(术语)
a)连接点:类里面哪些方法可以被增强,这些方法称为连接点
b)切入点:实际被真正增强的方法称为切入点
c)通知(增强):实际增强的逻辑部分称为通知,且分为以下五种类型:
1)前置通知 2)后置通知 3)环绕通知 4)异常通知 5)最终通知
d)切面:把通知应用到切入点过程
5、AOP操作
a)Spring 框架一般都是基于 AspectJ
实现 AOP 操作,AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使 用,进行 AOP 操作
b)基于 AspectJ 实现 AOP 操作:1)基于 xml 配置文件实现 (2)基于注解方式实现(使用)
c)引入相关jar包
d)切入点表达式,如下:
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )
(3)例子如下:
例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.atguigu.dao.BookDao.add(..))
例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (..))
例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))
6、AOP 操作(AspectJ 注解)
//1、创建类,在类里面定义方法
public class User {
public void add() {
System.out.println("add.......");
}
}
//2、创建增强类(编写增强逻辑)
//(1)在增强类里面,创建方法,让不同方法代表不同通知类型
//增强的类
public class UserProxy {
public void before() {//前置通知
System.out.println("before......");
}
}
<!--3、进行通知的配置-->
<?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:context="http://www.springframework.org/schema/context"
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/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="com.atguigu.spring5.aopanno"></context:component-scan>
<!-- 开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
//增强的类
@Component
@Aspect //生成代理对象
public class UserProxy {}
//被增强的类
@Component
public class User {}
//4、配置不同类型的通知
@Component
@Aspect //生成代理对象
public class UserProxy {
//相同切入点抽取
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void pointdemo() {
}
//前置通知
//@Before注解表示作为前置通知
@Before(value = "pointdemo()")//相同切入点抽取使用!
public void before() {
System.out.println("before.........");
}
//后置通知(返回通知)
@AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void afterReturning() {
System.out.println("afterReturning.........");
}
//最终通知
@After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void after() {
System.out.println("after.........");
}
//异常通知
@AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing.........");
}
//环绕通知
@Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前.........");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕之后.........");
}
}
7、有多个增强类对同一个方法进行增强,设置增强类优先级
//(1)在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy{ }
8、AOP 操作(AspectJ 配置文件)
<!--1、创建两个类,增强类和被增强类,创建方法(同上一样)-->
<!--2、在 spring 配置文件中创建两个类对象-->
<!--创建对象-->
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
<!--3、在 spring 配置文件中配置切入点-->
<!--配置 aop 增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
JdbcTemplate
1、JdbcTemplate概念及使用
a)Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作
b)引入相关 jar 包
c)在 spring 配置文件配置数据库连接池
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql:///test" />
<property name="username" value="root" />
<property name="password" value="root" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
d)配置 JdbcTemplate 对象,注入 DataSource
<!-- JdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入 dataSource-->
<property name="dataSource" ref="dataSource"></property><!--set方式注入-->
</bean>
e)创建 service 类,创建 dao 类,在 dao 注入 jdbcTemplate 对象
<!-- 组件扫描 -->
<context:component-scan base-package="com.atguigu"></context:component-scan>
@Service
public class BookService {
//注入 dao
@Autowired
private BookDao bookDao;
}
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
}
2、JdbcTemplate 操作数据库(添加)
a)对应数据库创建实体类
b)创建service和dao
(1)在 dao 进行数据库添加操作
(2)调用 JdbcTemplate 对象里面 update 方法实现添加操作
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加的方法
@Override
public void add(Book book) {
//1 创建 sql 语句
String sql = "insert into t_book values(?,?,?)";
//2 调用方法实现
Object[] args = {book.getUserId(), book.getUsername(),book.getUstatus()};
int update = jdbcTemplate.update(sql,args);
System.out.println(update);
}
}
3、JdbcTemplate 操作数据库(修改和删除)
//1、修改
@Override
public void updateBook(Book book) {
String sql = "update t_book set username=?,ustatus=? where user_id=?";
Object[] args = {book.getUsername(), book.getUstatus(),book.getUserId()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);
}
//2、删除
@Override
public void delete(String id) {
String sql = "delete from t_book where user_id=?";
int update = jdbcTemplate.update(sql, id);
System.out.println(update);
}
//使用JdbcTemplate 模板所实现的 “增删改” 都是调用了同一个 “update” 方法
4、JdbcTemplate 操作数据库(查询返回某个值)
//查询表记录数
@Override
public int selectCount() {
String sql = "select count(*) from t_book";
//queryForObject方法中:第一个参数代表--sql语句;第二个参数代表--返回类型class
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}
5、JdbcTemplate 操作数据库(查询返回对象)
//查询返回对象
@Override
public Book findBookInfo(String id) {
String sql = "select * from t_book where user_id=?";
//调用方法
/*
queryForObject方法中:
第一个参数:sql语句
第二个参数:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面 实现类 完成数据封装
第三个参数:sql 语句值
*/
Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
return book;
}
6、JdbcTemplate 操作数据库(查询返回集合)
//所用场景:查询图书列表分页、、
//查询返回集合
@Override
public List<Book> findAllBook() {
String sql = "select * from t_book";
//调用方法
List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
return bookList;
}
7、JdbcTemplate 操作数据库(批量操作)
//批量添加
@Override
public void batchAddBook(List<Object[]> batchArgs) {
String sql = "insert into t_book values(?,?,?)";
//batchUpdate方法 第一个参数:sql语句 第二个参数:List集合,添加多条记录数据
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
//批量添加测试
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {"3","java","a"};
Object[] o2 = {"4","c++","b"};
Object[] o3 = {"5","MySQL","c"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
//调用批量添加
bookService.batchAdd(batchArgs);
8、JdbcTemplate 实现批量修改操作
//批量修改(同批量添加一样,调用同一个方法)
@Override
public void batchUpdateBook(List<Object[]> batchArgs) {
String sql = "update t_book set username=?,ustatus=? where user_id=?";
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?