2025年Spring学习笔记

Spring学习笔记spring 概述 spring 是一个控制反转和面向切面的轻量级框架 组成 spring core 是一切的基石 为其他的组件提供支持 bean 容器管理就是在这个组件里 spring aop 为面向切面提供了丰富的支持 spring dao 封装整合了大量 jdbc 底层操作 spring orm 为集成 orm 框架提供了大量支持 spring

大家好,我是讯享网,很高兴认识大家。

spring

概述

spring是一个控制反转和面向切面的轻量级框架。

组成

  1. spring core 是一切的基石,为其他的组件提供支持,bean容器管理就是在这个组件里
  2. spring aop 为面向切面提供了丰富的支持
  3. spring dao 封装整合了大量jdbc底层操作
  4. spring orm 为集成orm框架提供了大量支持
  5. spring context 上下文管理,并且提供了一些企业级服务
  6. spring web 为web开发提供基本支持
  7. spring web mvc 提供了完整的mvc框架
    在这里插入图片描述
    讯享网

IOC(Inversion of Control)控制反转

概述

原本控制对象的权利在程序员手里,现在控制对象的权利在spring容器那里,对象控制权发生反转,故而称之为控制反转。

由来

举个例子,本来业务库用的是Mysql,现在改为使用Oracle,有两种方式可以来处理这个需求:
第一种方式,创建UserDao的权利在业务层,客户如果需要切换数据源需要开发人员手动切换;
第二种方式,通过set方法注入具体的UserDao信息,控制权移到了客户手里,客户需要什么数据源,那就创建什么数据源然后注入到业务层;

public interface UserDao { 
    void getUser(); } 

讯享网
讯享网public class MysqlUserDao implements UserDao { 
    public void getUser() { 
    System.out.println("mysql 拿到用户"); } } 
public class OracleUserDao implements UserDao { 
    public void getUser() { 
    System.out.println("oracle 拿到用户"); } } 
讯享网public class UserService { 
    //1.需要用什么类型的dao需要手动来这里改 //private UserDao userDao = new MysqlUserDao(); //2.通过set方式注入(把控制权交出去) private UserDao userDao; public void setUserDao(UserDao userDao) { 
    this.userDao = userDao; } public void getUser() { 
    userDao.getUser(); } } 
public class MyTest { 
    @Test public void client() { 
    UserService userService = new UserService(); userService.getUser(); } @Test public void iocClient() { 
    MysqlUserDao mysqlUserDao = new MysqlUserDao(); UserService userService = new UserService(); userService.setUserDao(mysqlUserDao); userService.getUser(); } } 

入门示例

引入依赖

讯享网<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.5</version> </dependency> 

由于webmvc会再自动依赖一些spring的核心包,所以只需要引入一个webmvc即可
在这里插入图片描述
编写实体类

package com.xubadou.pojo; / * @Package com.xubadou.pojo * @Author 徐八斗 * @Date 2021/7/10 10:15 * @Version V1.0 */ public class User { 
    private String name; private int age; public String getName() { 
    return name; } public void setName(String name) { 
    this.name = name; } public int getAge() { 
    return age; } public void setAge(int age) { 
    this.age = age; } @Override public String toString() { 
    return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } } 

创建applicationContext.xml配置文件,然后把实体类配置成bean

讯享网<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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="com.xubadou.pojo.User"> <property name="name" value="xubadou"/> <property name="age" value="99"/> </bean> </beans> 

创建测试类,获取bean

import com.xubadou.pojo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; / * @Package PACKAGE_NAME * @Author 徐八斗 * @Date 2021/7/10 10:20 * @Version V1.0 */ public class MyTest { 
    @Test public void getBean() { 
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = context.getBean("user", User.class); System.out.println(user.toString()); } } 

如下图所示,已经可以从spring容器中获取bean了
在这里插入图片描述

DI(DependencyInjection)依赖注入

概述

对象的创建依赖于容器,对象的属性需要容器进行注入。

bean的注入方式

构造器注入
讯享网package com.xn.pojo; / * @Package com.xn.pojo * @Author 徐八斗 * @Date 2021/7/10 10:28 * @Version V1.0 */ public class User { 
    private String name; public User(String name) { 
    this.name = name; } public String getName() { 
    return name; } public void setName(String name) { 
    this.name = name; } public void show() { 
    System.out.println("name = " + name); } } 

在xml文件中配置bean(构造器注入有三种方式进行配置,任选其一即可)

<!-- 第一种,下标赋值--> <bean id="user" class="com.xn.pojo.User"> <constructor-arg index="0" value="xhj"/> </bean> <!--第二种,通过类型赋值--> <!--<bean id="user" class="com.xn.pojo.User"> <constructor-arg type="java.lang.String" value="xhj"/> </bean>--> <!--第三种,通过参数名赋值--> <!--<bean id="user" class="com.xn.pojo.User"> <constructor-arg name="name" value="xhj"/> </bean>--> 

测试类同入门示例中相同,不再赘述

set 方法注入
讯享网package com.xn.pojo; import java.util.*; / * @Package com.xn.pojo * @Author 徐八斗 * @Date 2021/7/10 10:28 * @Version V1.0 */ public class Student { 
    private String name; private Address address; private String [] books; private List<String> hobbys; private Map<String, Object> card; private Set<String> games; private String wife; private Properties info; public String getName() { 
    return name; } public void setName(String name) { 
    this.name = name; } public Address getAddress() { 
    return address; } public void setAddress(Address address) { 
    this.address = address; } public String[] getBooks() { 
    return books; } public void setBooks(String[] books) { 
    this.books = books; } public List<String> getHobbys() { 
    return hobbys; } public void setHobbys(List<String> hobbys) { 
    this.hobbys = hobbys; } public Map<String, Object> getCard() { 
    return card; } public void setCard(Map<String, Object> card) { 
    this.card = card; } public Set<String> getGames() { 
    return games; } public void setGames(Set<String> games) { 
    this.games = games; } public String getWife() { 
    return wife; } public void setWife(String wife) { 
    this.wife = wife; } public Properties getInfo() { 
    return info; } public void setInfo(Properties info) { 
    this.info = info; } @Override public String toString() { 
    return "Student{" + "name='" + name + '\'' + ", address=" + address.toString() + ", books=" + Arrays.toString(books) + ", hobbys=" + hobbys + ", card=" + card + ", games=" + games + ", wife='" + wife + '\'' + ", info=" + info + '}'; } } 
package com.xn.pojo; / * @Package com.xn.pojo * @Author 徐八斗 * @Date 2021/7/10 10:28 * @Version V1.0 */ public class Address { 
    private String name; public String getName() { 
    return name; } public void setName(String name) { 
    this.name = name; } @Override public String toString() { 
    return "Address{" + "name='" + name + '\'' + '}'; } } 

配置bean,并注入各种类型的属性

讯享网<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="address" class="com.xn.pojo.Address"/> <bean id="student" class="com.xn.pojo.Student"> <!--第一种·普通值注入,value--> <property name="name" value="xhj"/> <!--第二种·bean注入,ref--> <property name="address" ref="address"/> <!--数组注入,array--> <property name="books"> <array> <value>红楼梦</value> <value>水浒传</value> <value>西游记</value> </array> </property> <!--list--> <property name="hobbys"> <list> <value>听歌</value> <value>跑步</value> <value>看电影</value> </list> </property> <!--map--> <property name="card"> <map> <entry key="身份证" value=""/> <entry key="银行卡" value=""/> </map> </property> <!--Set--> <property name="games"> <set> <value>LOL</value> <value>CF</value> </set> </property> <!--null--> <property name="wife"> <null/> </property> <!--Properties--> <property name="info"> <props> <prop key="学号">14312</prop> <prop key="性别"></prop> </props> </property> </bean> </beans> 

测试类同入门示例相差无几,不再赘述

其他方式注入

使用p命名空间、c命名空间进行注入
p命令空间继续使用入门示例
修改入门示例中的配置文件如下:

<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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--<bean id="user" class="com.xubadou.pojo.User"> <property name="name" value="xubadou"/> <property name="age" value="99"/> </bean>--> <!--使用p命名空间--> <bean id="user" class="com.xubadou.pojo.User" p:name="xubadou" p:age="99"/> </beans> 

然后执行测试类中的方法,可以发现结果是一样
在这里插入图片描述
c命令空间使用构造器注入的例子
在配置文件中加入约束

讯享网 xmlns:c="http://www.springframework.org/schema/c" 

然后bean 可以对应的改成

<bean id="user" class="com.xn.pojo.User" c:name="xhj"/> 

bean的作用域

配置bean的时候有个属性叫做scope,这个属性代表着bean的作用域,常见的作用域配置如下:
singleton:单例模式,只会创建一个对象,全局唯一;
prototype:原型模式,每次从容器中get的时候,都会创建一个新的对象;
下面三个只能在web项目中才可以使用
request:每次请求的时候,才会创建一个新的对象;
session: 每个会话只会创建一个对象;
global session:所有的会话只会创建一个对象;

bean的自动装配

所谓的自动装配,说通俗点就是把原本需要手动维护的bean之间的关联关系交给ioc容器去自动管理。

no

默认情况下,通过ref手动配置bean之间的依赖关系
举个例子
首先创建三个实体类:人、车、手机。而人,拥有车以及手机属性。

讯享网package com.xubadou.pojo; / * @Package com.xubadou.pojo * @Author 徐八斗 * @Date 2021/7/14 6:52 * @Version V1.0 */ public class Car { 
    public void run() { 
    System.out.println("开车"); } } 
package com.xubadou.pojo; / * @Package com.xubadou.pojo * @Author 徐八斗 * @Date 2021/7/14 6:52 * @Version V1.0 */ public class Phone { 
    public void call() { 
    System.out.println("打电话"); } } 
讯享网package com.xubadou.pojo; / * @Package com.xubadou.pojo * @Author 徐八斗 * @Date 2021/7/14 6:52 * @Version V1.0 */ public class Person { 
    private Car car; private Phone phone; public Car getCar() { 
    return car; } public void setCar(Car car) { 
    this.car = car; } public Phone getPhone() { 
    return phone; } public void setPhone(Phone phone) { 
    this.phone = phone; } @Override public String toString() { 
    return "Person{" + "car=" + car + ", phone=" + phone + '}'; } } 

创建配置文件

<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car" class="com.xubadou.pojo.Car"/> <bean id="phone" class="com.xubadou.pojo.Phone"/> <bean id="person" class="com.xubadou.pojo.Person"> <property name="car" ref="car"/> <property name="phone" ref="phone"/> </bean> </beans> 

编写测试类

讯享网import com.xubadou.pojo.Person; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; / * @Package PACKAGE_NAME * @Author 徐八斗 * @Date 2021/7/14 6:59 * @Version V1.0 */ public class MyTest { 
    @Test public void testByName() { 
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Person person = context.getBean("person", Person.class); person.getCar().run(); person.getPhone().call(); } } 

运行结果:
在这里插入图片描述

byName
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car" class="com.xubadou.pojo.Car"/> <bean id="phone" class="com.xubadou.pojo.Phone"/> <bean id="person" class="com.xubadou.pojo.Person" autowire="byName"/> </beans> 
byType
讯享网<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car" class="com.xubadou.pojo.Car"/> <bean id="phone" class="com.xubadou.pojo.Phone"/> <bean id="person" class="com.xubadou.pojo.Person" autowire="byType"/> </beans> 
注解

如果要使用注解的方式进行自动注入,首先要修改配置文件,添加context约束以及开启注解的使用

<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--开启注解--> <context:annotation-config/> <bean id="car" class="com.xubadou.pojo.Car"/> <bean id="phone2" class="com.xubadou.pojo.Phone"/> <bean id="phone1" class="com.xubadou.pojo.Phone"/> <bean id="person" class="com.xubadou.pojo.Person"/> </beans> 
@Autowired+@Qualifier

@Autowired首先根据属性的类型去找,如果通过类型没法确定,会再通过属性的名称去找,如果通过名称也无法找到唯一的bean的时候,可以使用@Qualifier来指定具体的bean的名称
注:@Autowired(required = false)的设置可以允许自动注入的属性为空
依旧使用上面的例子
修改person实体类

讯享网package com.xubadou.pojo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; / * @Package com.xubadou.pojo * @Author 徐八斗 * @Date 2021/7/14 6:52 * @Version V1.0 */ public class Person { 
    @Autowired private Car car; @Autowired @Qualifier("phone1") private Phone phone; public Car getCar() { 
    return car; } public Phone getPhone() { 
    return phone; } @Override public String toString() { 
    return "Person{" + "car=" + car + ", phone=" + phone + '}'; } } 
@Resource

@Resource也可以进行自动注入,首先通过属性的名称进行查找,如果没有找到,会再通过属性的类型进行查找,如果还是没找到,还可以执行bean的名称来进行查找

package com.xubadou.pojo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import javax.annotation.Resource; / * @Package com.xubadou.pojo * @Author 徐八斗 * @Date 2021/7/14 6:52 * @Version V1.0 */ public class Person { 
    @Resource private Car car; @Resource(name = "phone1") private Phone phone; public Car getCar() { 
    return car; } public Phone getPhone() { 
    return phone; } @Override public String toString() { 
    return "Person{" + "car=" + car + ", phone=" + phone + '}'; } } 

常用注解

@Component及其衍生注解
讯享网<bean id="" class=""/> 

衍生注解如下:
@Controller
标注于controller层的类
@Service
标注于service层的类
@Repository
标注于dao层的类

@Value

标注在属性上,用于属性的注入,等价于

<property name="" value=""/> 
@Scope

标注于类上,用于确定该bean的作用域

java配置类

@Configuration 代表这是一个配置类,相当于之前的applicationContext.xml配置文件,本身也是一个componet,会被注入容器
@Bean 相当于之前配置文件中的标签,标注与方法之上,返回类型相当于class,方法名相当于id
@ComponentScan(“com.xubadou”) 扫描包
@Import(BeanConfigExt.class) 引入其他的配置类

通过java 配置类就可以省略配置文件的编写工作

AOP(Aspect-oriented Programming)面向切面编程

先放概念:

通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术

代理模式

讯享网package com.xubadou; / * @Package com.xubadou * @Author 徐八斗 * @Date 2021/7/25 9:36 * @Version V1.0 */ public interface Saler { 
    void sale(); } 

然后编写生产厂家和代理商

package com.xubadou; / * @Package com.xubadou * @Author 徐八斗 * @Date 2021/7/25 9:36 * @Version V1.0 */ public class Factory implements Saler { 
    public void sale() { 
    System.out.println("生产商品"); } } 

代理商拿到商品后,可以进行销售

讯享网package com.xubadou; / * @Package com.xubadou * @Author 徐八斗 * @Date 2021/7/25 9:37 * @Version V1.0 */ public class Proxy implements Saler { 
    private Factory factory; public Proxy(Factory factory) { 
    this.factory = factory; } public void sale() { 
    factory.sale(); System.out.println("销售商品"); } } 

买方通过代理商拿到商品

package com.xubadou; / * @Package com.xubadou * @Author 徐八斗 * @Date 2021/7/25 9:38 * @Version V1.0 */ public class Buyer { 
    public static void main(String[] args) { 
    Factory factory = new Factory(); Proxy proxy = new Proxy(factory); proxy.sale(); } } 

Spring AOP

Spring AOP 底层是基于动态代理的,常用的框架如:jdk的动态代理,以及cglib的动态代理

动态代理

所谓的动态代理是指动态的生成代理类,而不用手动的编写代理类实现代理

jdk 动态代理

基于接口的动态代理,通过实现反射实现接口,生成代理类,所以只能针对接口
继续使用上面代理商的例子
首先编写类实现InvocationHandler

讯享网package com.xubadou.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; / * @Package com.xubadou.jdk * @Author 徐八斗 * @Date 2021/7/25 10:01 * @Version V1.0 */ public class JdkInvokeHandler implements InvocationHandler { 
    private Object target; public JdkInvokeHandler(Object target) { 
    this.target = target; } / * 获取代理对象 * @return */ public Object getProxy() { 
    return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
    Object result = method.invoke(target, args); System.out.println("销售商品"); return result; } } 

重新编写买方

package com.xubadou.jdk; import com.xubadou.Factory; import com.xubadou.Saler; / * @Package com.xubadou.jdk * @Author 徐八斗 * @Date 2021/7/25 10:04 * @Version V1.0 */ public class JdkBuyer { 
    public static void main(String[] args) { 
    Factory factory = new Factory(); JdkInvokeHandler jdkInvokeHandler = new JdkInvokeHandler(factory); Saler proxy = (Saler) jdkInvokeHandler.getProxy(); proxy.sale(); } } 

从上面的代码中可以看到,不再需要编写代理类了,具体的代理类可以通过jdk动态的生成,而最终的结果一致

cglib 动态代理
讯享网<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> 

首先编写类实现MethodInterceptor

package com.xubadou.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; / * @Package com.xubadou.cglib * @Author 徐八斗 * @Date 2021/7/25 10:14 * @Version V1.0 */ public class CglibInterceptor implements MethodInterceptor { 
    private Object target; public CglibInterceptor(Object target) { 
    this.target = target; } / * 获取代理类的实例 * @return */ public Object getProxy() { 
    Enhancer enhancer = new Enhancer(); // 设置父类为实例类 enhancer.setSuperclass(this.target.getClass()); // 回调方法 enhancer.setCallback(this); // 创建代理对象 return enhancer.create(); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 
    Object result = methodProxy.invokeSuper(o, objects); System.out.println("销售商品"); return result; } } 

改写生产厂家类,不实现Saler接口

讯享网package com.xubadou.cglib; import com.xubadou.Saler; / * @Package com.xubadou * @Author 徐八斗 * @Date 2021/7/25 9:36 * @Version V1.0 */ public class CglibFactory { 
    public void sale() { 
    System.out.println("生产商品"); } } 

改写买方

package com.xubadou.cglib; import com.xubadou.Factory; import com.xubadou.Saler; import com.xubadou.jdk.JdkInvokeHandler; / * @Package com.xubadou.jdk * @Author 徐八斗 * @Date 2021/7/25 10:04 * @Version V1.0 */ public class CglibBuyer { 
    public static void main(String[] args) { 
    CglibFactory factory = new CglibFactory(); CglibInterceptor cglibInterceptor = new CglibInterceptor(factory); CglibFactory proxy = (CglibFactory) cglibInterceptor.getProxy(); proxy.sale(); } } 

通过上面的例子可以看到,普通类也可以生成代理对象,并且结果保持一致

常见概念

横切关注点:跨越应用程序多个模块的方法或功能,与业务逻辑无关,但需要我们关注的部分,比如日志、安全、缓存、事务等
切面(Aspect):关注点模块化(切面类)
通知(Advice):在切面的某个特定的连接点执行的方法(切面类中的方法)
目标(Target):被通知的对象
代理(Proxy):向目标对象应用通知之后创建的对象
切入点(PointCut):切面通知执行地点的定义(匹配连接点的断言)
连接点(JointPoint):与切入点匹配的执行点

在这里插入图片描述通知有五种类型:
前置通知:方法执行前
后置通知:方法执行后
环绕通知:方法执行前后均可
异常通知:发生异常时执行
最后通知:方法返回结果后执行

执行顺序(spring版本不一样,顺序也会不一样,我这里用的是spring5.x):
1.无异常:
环绕前置》前置》方法》返回后置(AfterReturning)》后置(After)》环绕后置
2.有异常:
环绕前置》前置》方法》异常》后置(After)》环绕后置

讯享网<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> <scope>runtime</scope> </dependency> 

编写业务层接口及其实现

package com.xubadou.service; / * @Package com.xubadou.service * @Author 徐八斗 * @Date 2021/7/25 15:36 * @Version V1.0 */ public interface UserService { 
    void add(); void delete(); void update(); void select(); } 
讯享网package com.xubadou.service; / * @Package com.xubadou.service * @Author 徐八斗 * @Date 2021/7/25 15:37 * @Version V1.0 */ public class UserServiceImpl implements UserService { 
    public void add() { 
    System.out.println("添加"); } public void delete() { 
    System.out.println("删除"); } public void update() { 
    System.out.println("修改"); } public void select() { 
    System.out.println("查询"); } } 

编写前置通知以及后置通知

package com.xubadou.aspect; import org.springframework.aop.BeforeAdvice; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; / * @Package com.xubadou.aspect * @Author 徐八斗 * @Date 2021/7/25 15:38 * @Version V1.0 */ public class BeforeAspect implements MethodBeforeAdvice { 
    / * * @param method 目标对象的待执行的方法 * @param args 参数 * @param target 目标对象 * @throws Throwable */ public void before(Method method, Object[] args, Object target) throws Throwable { 
    System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了"); } } 
讯享网package com.xubadou.aspect; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; / * @Package com.xubadou.aspect * @Author 徐八斗 * @Date 2021/7/25 15:42 * @Version V1.0 */ public class AfterAspect implements AfterReturningAdvice { 
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { 
    System.out.println("执行了" + method.getName() + "方法"); } } 

编写配置文件

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--注册bean--> <bean id="userService" class="com.xubadou.service.UserServiceImpl"/> <bean id="beforeAspect" class="com.xubadou.aspect.BeforeAspect"/> <bean id="afterAspect" class="com.xubadou.aspect.AfterAspect"/> <aop:config> <aop:pointcut id="pointcut" expression="execution(* com.xubadou.service.UserServiceImpl.*(..))"/> <aop:advisor advice-ref="beforeAspect" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterAspect" pointcut-ref="pointcut"/> </aop:config> </beans> 

编写测试类

讯享网import com.xubadou.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; / * @Package PACKAGE_NAME * @Author 徐八斗 * @Date 2021/7/25 15:49 * @Version V1.0 */ public class MyTest { 
    @Test public void testAop() { 
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = context.getBean("userService", UserService.class); userService.add(); userService.delete(); userService.update(); userService.select(); } } 

运行结果如下:
在这里插入图片描述如上图可以看到前置通知和后置通知都执行了

常用注解

<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> <scope>runtime</scope> </dependency> <dependency> <groupId>aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.5.4</version> </dependency> 

编写使用注解的切面类

讯享网package com.xubadou.anno; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; / * @Package com.xubadou.anno * @Author 徐八斗 * @Date 2021/7/25 16:09 * @Version V1.0 */ @Aspect public class AnnotationAspect { 
    @Before("execution(* com.xubadou.service.UserServiceImpl.*(..))") public void before() { 
    System.out.println("方法执行前"); } @After("execution(* com.xubadou.service.UserServiceImpl.*(..))") public void after() { 
    System.out.println("方法执行后"); } @Around("execution(* com.xubadou.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint joinPoint) { 
    System.out.println("环绕前"); try { 
    joinPoint.proceed(); } catch (Throwable throwable) { 
    throwable.printStackTrace(); } System.out.println("环绕后"); } @AfterReturning("execution(* com.xubadou.service.UserServiceImpl.*(..))") public void afterReturning() { 
    System.out.println("方法返回之后"); } @AfterThrowing("execution(* com.xubadou.service.UserServiceImpl.*(..))") public void afterThrowing() { 
    System.out.println("方法抛出异常"); } } 

添加配置

<bean id="annotationAspect" class="com.xubadou.anno.AnnotationAspect"/> <!--开启aop注解--> <aop:aspectj-autoproxy/> 
小讯
上一篇 2025-04-04 23:56
下一篇 2025-02-05 18:04

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/28375.html