【Spring框架精讲】进阶指南:企业级Java应用的核心框架(Spring5)

news2024/11/22 20:28:23

文章目录

  • 【Spring框架精讲】进阶指南:企业级Java应用的核心框架(Spring5)
    • 1.Spring框架快速入门
      • 1.1七大核心模块
        • 1.1.1 Spring Core
        • 1.1.2 Spring-Beans
        • 1.1.3 Spring Context
        • 1.1.4 Spring-Expression
        • 1.1.5 Spring AOP
        • 1.1.6 JDBC和DAO模块(Spring DAO)
        • 1.1.7 spring-transaction
        • 1.1.8 Spring ORM
        • 1.1.9 Spring Web MVC
      • 1.2 项目构建
    • 2.SpringIOC
      • 2.1反射创建对象
      • 2.2 IOC核心的接口
      • 2.3 ApplicationContext主要实现类
    • 3.SpringBean的注入方式
      • 3.1 创建对象和set方法、有参构造函数注入属性
      • 3.2注入空值和特殊符号
      • 3.3注入属性外部bean
      • 3.4注入内部bean(应用较少)
      • 3.5注入级联赋值
      • 3.6注入集合类型属性
      • 3.7注入集合类型为对象属性
      • 3.8集合注入部分提取公共
      • 3.9 IOC操作Bean的管理
    • 4.Spring的工厂Bean
      • 4.1 SpringBean的作用域
      • 4.2 SpringBean的生命周期
      • 4.3 SpringBean的自动装配
    • 5.SpringBean的AOP
      • 5.1代理模式
        • 5.1.1 代理模式创建方式
        • 5.1.2 静态代理
        • 5.1.3 动态代理
      • 5.2 AOP详解
        • 5.2.1 Aop常用术语
        • 5.2.2 Aop环境准备

【Spring框架精讲】进阶指南:企业级Java应用的核心框架(Spring5)

JDK最低版本要求1.8

Spring概念
Spring是一个JavaEE开源的轻量级别的框架,可以解决我们企业开发中遇到的难题,它提供了依赖注入(DI)和面向切面编程(AOP)等功能。依赖注入可以简化对象之间的依赖关系管理,面向切面编程可以将一些横切关注点(例如事务管理、日志记录等)从核心业务逻辑中解耦出来。能够让编码变的更加简单,核心组件 IOC容器和Aop面向切面编程。

  1. IOC 控制反转:把整个对象创建的过程,统一交给我们SpringIOC容器来实现管理,底层使用反射+工厂模式实现。
  2. Aop面向切面编程:对我们功能(方法)前后实现增强,比如打印日志、事务原理、权限管理,底层是基于动态代理模式实现的。
    减少到我们的代码的冗余性问题。

Spring优势

  1. 方法的解耦,简化开发;
  2. Aop技术的支持;
  3. 提供声明事务支持
  4. Junit单元测试
  5. 方便整合其他框架(MybatisSpringMVCSpringBootSpringCloudRedis等)
  6. 降低我们的JavaEEapi开发使用的难度(Spring对很多复杂的api接口实现了封装)

Spring与SpringBoot关系
SpringBoot直接采用注解化的方式启动,底层会依赖于Spring/SpringMVC注解方式启动。
总结:SpringBoot底层基于Spring/SpringMVC注解化方式实现包装。

比如

  1. @RestController
  2. @ComponentScan("com.mayikt.aop")
  3. @Configuration
  4. @Component
  5. @Scheduled
  6. @Value
  7. @Bean

1.Spring框架快速入门

Spring的官网
Spring官方下载依赖jar包\

1.1七大核心模块

在这里插入图片描述

test
对应spring-test.jar. Spring提供的测试工具, 可以整合JUnit测试, 简化测试环节.

Core Container
Spring的核心组件, 包含了Spring框架最基本的支撑.
Beans, 对应spring-beans.jar. Spring进行对象管理时依赖的jar包.
Core, 对应spring-core.jar, Spring核心jar包.
Context, 对应spring-context.jar, Spring容器上下文对象.
SpEL, 对应spring-expression.jar, Spring表达式语言.

AOP
面向切面编程, 对应spring-aop.jar.

Data Access
Spring对数据访问层的封装
JDBC, 对应spring-jdbc.jar. Spring对jdbc的封装, 当需要使用spring连接数据库时使用. spring-jdbc.jar需要依赖spring-tx.jar.
Transactions, 对应spring-tx.jar. 事务管理
ORM, 对应spring-orm.jar. spring整合第三方orm框架需要使用的jar包, 例如Hibernate框架.

Web
Spring对javax下的接口或类做的扩展功能.
spring-web.jar, 对Servlet, filter, Listener等做的增强.
spring-webmvc.jar, 实际上就是SpringMVC框架. 需要依赖spring环境和spring-web.jar.

1.1.1 Spring Core

核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。

Maven依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
1.1.2 Spring-Beans

这个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion ofControl / Dependency Injection(IoC/DI)操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar 及spring-beans.jar 文件就可以了。
外部依赖spring-core,(CGLIB)

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
1.1.3 Spring Context
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>

Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。

1.1.4 Spring-Expression

模块提供了一个强大的表达式语言,用于在运行时查询和处理对象图。该语言支持设置和获取属性值;属性赋值,方法调用,访问数组的内容,收集和索引器,逻辑和算术运算,命名变量,并从Spring的IOC容器的名字对象检索,它也支持列表选择和投影以及常见的列表聚合。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
1.1.5 Spring AOP

通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
1.1.6 JDBC和DAO模块(Spring DAO)

JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
1.1.7 spring-transaction

以前是在这里org.springframework.transaction
为JDBC、Hibernate、JDO、JPA、Beans等提供的一致的声明式和编程式事务管理支持。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
1.1.8 Spring ORM

Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
1.1.9 Spring Web MVC

MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>

1.2 项目构建

Maven依赖

<dependencies>
    <!--
     这个jar 文件包含Spring 框架基本的核心工具类。Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统中使用这些工具类。
外部依赖Commons Logging, (Log4J)。
     -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>
    <!--
    这个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion ofControl / Dependency Injection(IoC/DI)操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar 及spring-beans.jar 文件就可以了。
外部依赖spring-core,(CGLIB)。
    -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>
    <!--
这个jar 文件为Spring 核心提供了大量扩展。可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。
外部依赖spring-beans, (spring-aop)。
    -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>


</dependencies>

创建spring.xml文件
在 resources 目录下创建

<?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">

    <!--
     配置SpringBean对象
     -->
    <bean id="userEntity" class="com.zhaoli.entity.UserEntity"></bean>

</beans>

获取Bean对象
在test\java 目录下创建 Test01类

//new UserEntity()
// 1.读取xml配置文件
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
// 2.根据bean的id获取bean对象
UserEntity userEntity = classPathXmlApplicationContext.getBean("userEntity", UserEntity.class);
System.out.println(userEntity);
userEntity.addUser();

2.SpringIOC

IOC容器底层实现原理;

  1. IOC容器中非常核心的接口 BeanFactory
    BeanFactory
    Bean对象 Factory工厂
  2. IOC容器基本的概念:控制反转
    把对象的创建过程与使用统一都交给我们的Spring来进行原理。
    不需要开发者自己去new对象
  3. IOC容器底层实现技术:反射技术、解析xml、工厂模式
  4. IOC作用 降低我们代码的耦合度。

创建对象的方式有那些:

  1. 单独new方式—耦合度太高了
    每次单独new对象,没有实现统一管理对象,如果后期userDao的名称信息发生变化的情况下,需要改变的引用地方比较多,耦合度太高。
  2. 工厂模式—降低我们耦合度
    概念:统一的管理和维护我们每个对象创建与使用的过程。
    不需要自己new对象。
  3. 反射的方式
    降低代码的-耦合度

com.zhaoli.dao—数据库访问层;
com.zhaoli.service—业务逻辑层;
业务逻辑层调用到数据库访问层

2.1反射创建对象

SpringIOC容器底层实现原理:
反射+工厂模式+解析xml技术实现

  1. 使用解析xml技术 解析spring.xml配置文件;
  2. 获取 类的完整路径地址
  3. 使用到反射技术初始化对象
  4. 需要使用工厂模式封装初始化对象

UserDaoFactory

public class UserDaoFactory {
    public static UserDao getUserDao(){
        return new UserDao();
    }
}
UserFactort
public class UserFactort {
    public static UserEntity getUserEntity() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //使用到反射技术初始化对象
        Class<?> aClass = Class.forName("com.zhaoli.entity.UserEntity");
        //默认执行的是无参构造函数
        UserEntity userEntity = (com.zhaoli.entity.UserEntity) aClass.newInstance();
        return userEntity;
    }
}

使用解析 xml 技术解析 spring.xml 配置文件 应用 dom4j 技术
UserFactort

public class UserFactort {
    public static UserEntity getUserEntity() throws ClassNotFoundException, InstantiationException, IllegalAccessException, DocumentException {
        //使用解析 xml 技术解析 spring.xml 配置文件 应用 dom4j 技术
        String userClass = new Dom4jClass().getUserClass();
        //使用到反射技术初始化对象
        Class<?> aClass = Class.forName(userClass);
        //默认执行的是无参构造函数
        UserEntity userEntity = (com.zhaoli.entity.UserEntity) aClass.newInstance();
        return userEntity;
    }
}

com/zhaoli/utils/Dom4jClass.java

public class Dom4jClass {
    public String getUserClass() throws DocumentException {
        //this.getClass().getResource() 动态获取到 resources 的绝对路径
        File xmlFile = new File(this.getClass().getResource("/") + "spring.xml");
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(xmlFile);
        //获取到根节点
        Element rootElement = document.getRootElement();
        //获取到 beans 中的 bean 标签
        Element bean = rootElement.element("bean");
        String aClass = bean.attributeValue("class");
        return aClass;
    }
}

Test02

UserEntity userEntity = UserFactort.getUserEntity();
System.out.println(userEntity);
userEntity.addUser();

2.2 IOC核心的接口

  1. IOC的核心思想底层基于反射+工厂模式实现
  2. Spring提供IOC容器实现两种方式:
    • BeanFactory IOC容器基本的实现,是spring内部自己使用的接口,不提供给开发者使用。
      加载配置文件过程的时候,不会创建对象,当我们在获取对象的时候才会获取创建对象。
    • ApplicationContext 是 BeanFactory 接口的子接口,提供更多的强大功能,适合于开发者使用。当我们在加载配置文件的过程中,就会将配置文件中的对象创建。

在做服务器端开发的时候,使用ApplicationContext 比较多,因为所有bean初始化操作在项目启动完成之前都已经初始化了。

2.3 ApplicationContext主要实现类

ClassPathXmlApplicationContext:对应类路径下的XML格式的配置文件
FileSystemXmlApplicationContext:对应文件系统中的XML格式的配置文件
ConfigurableApplicationContextApplicationContext的子接口,包含一些扩展方法
refresh()close()ApplicationContext具有启动、关闭和刷新上下文的能力。所以要关闭ApplicationContext需要new此接口的对象调用close()方法
WebApplicationContext 专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作

3.SpringBean的注入方式

3.1 创建对象和set方法、有参构造函数注入属性

  1. 什么是Bean管理
    使用spring创建对象、使用spring注入属性
  2. Bean的管理有两种方式
  • 基于XML方式配置
<bean id="userEntity" class="com.zhaoli.entity.UserEntity"></bean>

在spring的配置文件中,会配置一个bean标签,注入bean的信息,创建bean对象
Id:获取bean对象,唯一bean对象的名称; bean的名称不允许重复
Class属性:类的完整路径地址(类名称+包名称)
默认底层使用反射技术执行无参数构造函数

  • 基于XML方式注入属性
    DI 依赖注入: 对象的属性注入值; (spring实现)

(1)第一种实现方式:基于对象属性set方法实现

<!-- set方法注入属性值 -->    
<bean id="bookEntity" class="com.zhaoli.entity.BookEntity">
        <property name="bookName" value="面试宝典" ></property>
        <property name="bookPrice" value="88.8" ></property>
</bean>

在Bean 标签下再定义一个属性标签
name:类中的属性名称
value:需要注入的属性值

(2)第二种实现方式:有参构造函数注入属性
实例类 OrderEntity

public class OrderEntity {
    private String orderId;
    private String orderName;
    public OrderEntity() {
    }
    public OrderEntity(String orderId, String orderName) {
        this.orderId = orderId;
        this.orderName = orderName;
        System.out.println("反射机制执行到有参构造函数:"+orderId+";"+orderName);
    }
    @Override
    public String toString() {
        return "OrderEntity{" +
                "orderId='" + orderId + '\'' +
                ", orderName='" + orderName + '\'' +
                '}';
    }
}

Xml配置文件 order.xml

<!-- 第一种方式 指定参数列表名称注入参数 -->
<bean id="orderEntity" class="com.zhaoli.entity.OrderEntity">
    <constructor-arg name="orderId" value="123456"></constructor-arg>
    <constructor-arg name="orderName" value="赵立"></constructor-arg>
</bean>
<!-- 第二种方式 指定参数列表索引注入参数 -->
<bean id="orderEntity" class="com.zhaoli.entity.OrderEntity">
    <constructor-arg index="0" value="123456"></constructor-arg>
    <constructor-arg index="1" value="赵立"></constructor-arg>
</bean>

(3)第三种实现方式:p名称空间注入(应用较少)
xml头部引入P标签
xmlns:p="http://www.springframework.org/schema/p"
使用p标签注入属性:

<!-- p标签方式注入属性值 实际上最终还是走set方法   -->
<bean id="bookEntity" class="com.zhaoli.entity.BookEntity" 
p:bookName="面试宝典aaa" p:bookPrice="99.9"></bean>

3.2注入空值和特殊符号

1.注入空值属性

<bean id="bookEntity" class="com.zhaoli.entity.BookEntity">
    <property name="bookName">
        <null></null>
    </property>
    <property name="bookPrice" value="88.8" ></property>
</bean>

给bookName赋值为空

2.注入特殊符号
(1)转义注入方式
<< 转移为:&lt;&lt;
>>转移为:&gt;&gt;

<!-- 注入特殊符号 例如 < > -->
<!-- (1)转义注入方式 -->
<bean id="bookEntity" class="com.zhaoli.entity.BookEntity">
<!--    <property name="bookName" value="<<面试宝典>>" ></property>-->
    <property name="bookName" value="&lt;&lt;面试宝典&gt;&gt;" ></property>
    <property name="bookPrice" value="88.8" ></property>
</bean>

(2)cdata注入方式

<![CDATA[ 需要注入的内容  ]]>
<!-- (2)cdata注入方式 -->
<bean id="bookEntity" class="com.zhaoli.entity.BookEntity">
    <property name="bookName">
        <value><![CDATA[<<面试宝典aaa>>]]></value>
    </property>
    <property name="bookPrice" value="88.8" ></property>
</bean>

3.3注入属性外部bean

com.zhaoli.dao.MemberDao(接口)

public interface MemberDao {
    void addMember();
}
com.zhaoli.dao.MemberDaoImpl(实现类)
public class MemberDaoImpl implements MemberDao{
    @Override
    public void addMember() {
        System.out.println(">>MemberDao.addMember()<<");
    }
}
com.zhaoli.service.MemberService
public class MemberService {
    /**
     * 使用到属性注入的方式
     */
    private MemberDao memberDao;

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    public void addMember() {
        System.out.println(">MemberService.addMember()<");
        memberDao.addMember();
    }
}

Resources\member.xml

<!-- 将memberService注入到ioc容器中 -->
<bean id="memberService" class="com.zhaoli.service.MemberService">
    <!--
        name="memberDao" MemberService类中属性的名称
        ref="memberDao" 在ioc容器中注入的 beanid
     -->
    <property name="memberDao" ref="memberDao"></property>
</bean>
<!-- 将memberDao注入到ioc容器中 -->
<bean id="memberDao" class="com.zhaoli.dao.MemberDaoImpl"></bean>

Test

public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new
 ClassPathXmlApplicationContext("member.xml");
        MemberService memberService = (MemberService) app.getBean("memberService");
        memberService.addMember();
    }

3.4注入内部bean(应用较少)

  1. 数据库表 一对多或者一对一的关系
  2. 部门–n多个员工 一对多
  3. 站在员工角度考虑 员工属于那个部门
  4. 站在部门的角度考虑 部门下n多个员工
    员工对象 EmpEntity
public class EmpEntity {
    private String name;
    private String addres;//住址

    /**
     * 员工属于那个部门
     */
private DeptEntity deptEntity;
}

部门对象 DeptEntity

public class DeptEntity {
    private String name;//部门名称
}

Resources\spring_02.xml

<!-- 注入内部bean对象 -->
<bean id="empEntity" class="com.zhaoli.entity.EmpEntity">
    <property name="name" value="赵立"></property>
    <property name="addres" value="陕西省西安市"></property>
<!-- 注入内部bean对象 -->
    <property name="deptEntity">
        <bean id="deptEntity" class="com.zhaoli.entity.DeptEntity">
            <property name="name" value="开发部门"></property>
        </bean>
    </property>
</bean>

Test

public static void main(String[] args) {
    ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring_02.xml");
    EmpEntity empEntity = (EmpEntity) app.getBean("empEntity");
    System.out.println(empEntity);
}

注意:两个实体类都要生成 set()方法。

3.5注入级联赋值

实体类 员工对象和部门对象同3.4
写法一
Resources\spring_03.xml

<!-- 级联赋值的形式 -->
    <bean id="empEntity" class="com.zhaoli.entity.EmpEntity">
        <property name="name" value="赵立"></property>
        <property name="addres" value="陕西省西安市"></property>
        <!-- 级联赋值的形式 -->
        <property name="deptEntity" ref="deptEntity"></property>
    </bean>
    <!-- 注入部门对象 -->
<bean id="deptEntity" class="com.zhaoli.entity.DeptEntity">
<property name="name" value="教育部门"></property>
</bean>

写法二
Resources\spring_03.xml

<!-- 级联赋值的形式 -->
<bean id="empEntity" class="com.zhaoli.entity.EmpEntity">
    <property name="name" value="赵立"></property>
    <property name="addres" value="陕西省西安市"></property>
    <!-- 级联赋值的形式 -->
    <property name="deptEntity" ref="deptEntity"></property>
    <property name="deptEntity.name" value="IT部门"></property>
</bean>
<!-- 注入部门对象 -->
<bean id="deptEntity" class="com.zhaoli.entity.DeptEntity"></bean>

注意:需要在员工实体类新增:deptEntityGet()方法。

3.6注入集合类型属性

实体类 StuEntity

public class StuEntity {
    private String[] arrays;
    private List<String> list;
    private Map<String, String> map;
    private Set<String> set;
}

Resources\spring_04.xml

<bean id="stuEntity" class="com.zhaoli.entity.StuEntity">
    <!-- 对 arrays 属性赋值 -->
    <property name="arrays">
        <array>
            <value>arrays000</value>
            <value>arrays111</value>
        </array>
    </property>
    <!-- 对 list 属性赋值 -->
    <property name="list">
        <list>
            <value>list000</value>
            <value>list111</value>
        </list>
    </property>
    <!-- 对 map属性赋值 -->
    <property name="map">
        <map>
            <entry key="000" value="赵立"></entry>
            <entry key="111" value="樊靖"></entry>
        </map>
    </property>
    <!-- 对 set 属性赋值 -->
    <property name="set">
        <set>
            <value>set000</value>
            <value>set111</value>
        </set>
    </property>
</bean>

Test

public static void main(String[] args) {
     ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring_04.xml");
     StuEntity stuEntity = (StuEntity) app.getBean("stuEntity");
     System.out.println(stuEntity);
 }

3.7注入集合类型为对象属性

实体类 StuEntity

public class StuEntity {
    private String[] arrays;
    private List<String> list;
    private Map<String, String> map;
private Set<String> set;
/**
* 一名学生可以上 n 多门课程
*/
private List<CourseEntity> courses;
}
实体类  CourseEntity
public class CourseEntity {
private String name;
}

Resources\spring_04.xml

<bean id="stuEntity" class="com.zhaoli.entity.StuEntity">
    <!-- 对 arrays 属性赋值 -->
    <property name="arrays">
        <array>
            <value>arrays000</value>
            <value>arrays111</value>
        </array>
    </property>
    <!-- 对 list 属性赋值 -->
    <property name="list">
        <list>
            <value>list000</value>
            <value>list111</value>
        </list>
    </property>
    <!-- 对 map属性赋值 -->
    <property name="map">
        <map>
            <entry key="000" value="赵立"></entry>
            <entry key="111" value="樊靖"></entry>
        </map>
    </property>
    <!-- 对 set 属性赋值 -->
    <property name="set">
        <set>
            <value>set000</value>
            <value>set111</value>
        </set>
    </property>
    <!-- 对 courses 属性赋值(集合的类型为对象) -->
    <property name="courses">
        <list>
            <ref bean="courseEntity_java"></ref>
            <ref bean="courseEntity_dsj"></ref>
        </list>
    </property>
</bean>
<!-- java课程 -->
<bean id="courseEntity_java" class="com.zhaoli.entity.CourseEntity">
    <property name="name" value="java课程"></property>
</bean>
<!-- 大数据 -->
<bean id="courseEntity_dsj" class="com.zhaoli.entity.CourseEntity">
    <property name="name" value="大数据"></property>
</bean>

Test

public static void main(String[] args) {
    ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring_04.xml");
    StuEntity stuEntity = (StuEntity) app.getBean("stuEntity");
    System.out.println(stuEntity);
}

3.8集合注入部分提取公共

xml头部引入util标签

<?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:util="http://www.springframework.org/schema/util"
       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-util.xsd">
使用util标签提取公共部分:
<!-- 提取公共部分 -->
<util:list id="list">
    <value>zhaoli001</value>
    <value>zhaoli002</value>
</util:list>

<bean id="stuEntity" class="com.zhaoli.entity.StuEntity">
    <!-- 对 list 属性赋值 -->
    <property name="list" ref="list"></property>
</bean>

3.9 IOC操作Bean的管理

  1. Spring中两种类型bean,一种是为普通的bean,另外一种是工厂bean FactoryBean
  2. 普通Bean:在配置文件中定义什么类型与返回的类型需一致;
  3. 工厂Bean:在配置文件中定义Bean类型与返回类型可以不一致;

创建一个类,这个类是为工厂Bean,实现FactoryBean接口

4.Spring的工厂Bean

4.1 SpringBean的作用域

什么是作用域?设定bean作用域是为单例还是多例
作用域单例与多例有什么区别呢?

  1. 单例的作用域:每次在调用getbean方法获取对象都是为同一个对象。
  2. 多例的作用域:每次在调用getbean方法获取对象都是一个新的对象。

注意:在spring默认的情况下,bean的作用域就是为单例,节约服务器内存。
单例:在同一个jvm中,该bean对象只会创建一次。
多例:在同一个jvm中,该bean对象可以被创建多次。

设定对象单例还是多例
在spring的默认的情况下,springbean的作用域为单例。

  1. 单例就是每次获取bean都是同一个对象;
  2. 多例就是每次获取bean都是新的一个对象;
    单例:在同一个jvm中该bean只能存在一个实例;
    多例:在同一个jvm中该bean存在多个实例;
    证明:如果是为单例,则两个对象地址都是一样的,多例子对象则两个对象地址不一样。

单例配置:(默认就是为单例子)
<bean id="userEntity" class="com.mayikt.entity.UserEntity" scope="singleton"></bean>
多例配置:
<bean id="userEntity" class="com.mayikt.entity.UserEntity" scope="prototype"></bean>

4.2 SpringBean的生命周期

简单分为:实例化→属性赋值→初始化→销毁

生命周期概念:对象的创建与销毁的过程,类似之前学习servlet生命的周期过程。

生命周期的原理:

  1. 通过构造函数创建bean对象(默认执行无参构造函数 底层基于反射实现)
  2. 为bean的属性设置(使用反射调用set方法)
  3. 调用bean的初始化的方法(需要单独在类中配置初始化的方法)
  4. 正常使用bean对象
  5. Spring容器关闭,调用该类的销毁回调的方法(需要单独在类中配置销毁的方法)

com.zhaoli.entity.MemberEntity

public class MemberEntity {
    private String name;
    public MemberEntity(){
        System.out.println("[第一步流程:]执行MemberEntity无参构造函数");
    }

    public void setName(String name) {
        System.out.println("[第二步流程:]执行setName方法");
        this.name = name;
    }
    public void init(){
        System.out.println("[第三步流程:]调用init方法");
    }
    public void destroy(){
        System.out.println("[第五步流程:]调用destroy方法");
    }
}

Resources\spring_06.xml

<!--
        初始化的方法  init-method="init"
        销毁回调的方法  destroy-method="destroy"
    -->
<bean id="memberEntity" class="com.zhaoli.entity.MemberEntity" init-method="init" destroy-method="destroy">
    <property name="name" value="赵立"></property>
</bean>

test

public static void main(String[] args) {
    ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring_06.xml");
    MemberEntity memberEntity = app.getBean("memberEntity", MemberEntity.class);
    System.out.println("[第四步流程:]获取使用到的memberEntity");
    app.close();//手动让 bean 容器销毁
}

在这里插入图片描述

Bean的后置处理器 作用提供更多的扩展功能 BeanPostProcessor

  1. 通过构造函数创建bean对象(默认执行无参构造函数 底层基于反射实现)
  2. 为bean的属性设置 (使用反射调用set方法)
  3. 将bean传递给后置处理器 调用初始化方法之前执行
  4. 调用bean的初始化的方法(需要单独在类中配置初始化的方法)
  5. 将bean传递给后置处理器 调用初始化方法之后执行
  6. 正常使用bean对象
  7. Spring容器关闭,调用该类的销毁回调的方法(需要单独在类中配置销毁的方法)

com.zhaoli.entity.MemberEntity 同上
com.zhaoli.bean.MyPostProcessor

public class MyPostProcessor implements BeanPostProcessor {
    /**
     * 调用 init 方法之前处理
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[后置处理器调用init方法之前执行操作..]");
        return bean;
    }

    /**
     * 调用 init 方法之后处理
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[后置处理器调用init方法之后执行操作..]");
        return bean;
    }
}

Resources\spring_06.xml (加上下面内容)

<!-- 注册 bean 对象的后置处理器 MyPostProcessor  -->
<bean id="myPostProcessor" class="com.zhaoli.bean.MyPostProcessor"></bean>

Test 同上
在这里插入图片描述

配置多个 BeanPostProcessor

实现Ordered接口重写 getOrder()方法 返回的值越小越优先加载
com.zhaoli.bean.MyPostProcessor

public class MyPostProcessor implements BeanPostProcessor, Ordered {
    /**
     * 调用 init 方法之前处理
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[后置处理器调用init方法之前执行操作..]");
        return bean;
    }

    /**
     * 调用 init 方法之后处理
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[后置处理器调用init方法之后执行操作..]");
        return bean;
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

com.zhaoli.bean.MyPostProcessor2

public class MyPostProcessor2 implements BeanPostProcessor, Ordered {
    /**
     * 调用 init 方法之前处理
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[MyPostProcessor2:][后置处理器调用init方法之前执行操作..]");
        return bean;
    }

    /**
     * 调用 init 方法之后处理
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[MyPostProcessor2:][后置处理器调用init方法之后执行操作..]");
        return bean;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

Resources\spring_06.xml

<!--
    初始化的方法  init-method="init"
    销毁回调的方法  destroy-method="destroy"
-->
<bean id="memberEntity" class="com.zhaoli.entity.MemberEntity" init-method="init" destroy-method="destroy">
    <property name="name" value="赵立"></property>
</bean>
<!-- 注册 bean 对象的后置处理器 MyPostProcessor  -->
<bean id="myPostProcessor" class="com.zhaoli.bean.MyPostProcessor"></bean>
<!-- 注册 bean 对象的后置处理器 MyPostProcessor2  -->
<bean id="myPostProcessor2" class="com.zhaoli.bean.MyPostProcessor2"></bean>

Test 同上
在这里插入图片描述

4.3 SpringBean的自动装配

bean 标签中有一个属性 autowire

  1. byName 根据属性的名称自动装配 bean的id名称与属性的名称一致
  2. byType 根据属性的类型自动装配 bean的类型与属性类型一致(不能配置多个部门对象)

员工对象 EmpEntity

public class EmpEntity {
    private String name;
    private String addres;//住址

    /**
     * 员工属于那个部门
     */
private DeptEntity deptEntity;
}

部门对象 DeptEntity

public class DeptEntity {
private String name;//部门名称
}

根据属性的名称自动装配 bean的id名称与属性的名称一致

<!-- 注入内部bean对象 -->
<bean id="empEntity" class="com.zhaoli.entity.EmpEntity" autowire="byName">
    <property name="name" value="赵立"></property>
    <property name="addres" value="陕西省西安市"></property>
</bean>

<!-- 注入部门对象  -->
<bean id="deptEntity" class="com.zhaoli.entity.DeptEntity">
    <property name="name" value="开发部门"></property>
</bean>

根据属性的类型自动装配 bean的类型与属性类型一致

<!-- 注入内部bean对象 -->
<bean id="empEntity" class="com.zhaoli.entity.EmpEntity" autowire="byType">
    <property name="name" value="赵立"></property>
    <property name="addres" value="陕西省西安市"></property>
</bean>

<!-- 注入部门对象  -->
<bean id="deptEntity" class="com.zhaoli.entity.DeptEntity">
    <property name="name" value="开发部门"></property>
</bean>

5.SpringBean的AOP

AOP基本的概念
AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面,即解剖对象的内部,将那些影响了多个类的公共行为抽取到一个可重用模块里,减少系统的重复代码,降低模块间的耦合度,增强代码的可操作性和可维护性。

AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理、增强处理。

简单理解:
Aop面向切面编程,在方法之前和之后实现处理 应用场景在于:日志打印、事务实现、安全、权限控制、自定义注解等。 因为AOP可以解决我们程序上的代码冗余问题。

AOP 底层基于代理设计模式封装
代理设计模式 静态代理与动态代理
动态代理 jdk动态代理与 cglib动态代理

通俗易懂 aop 在我们的目标方法之前和之后处理的操作
开启事务
目标方法
提交或者回滚事务

5.1代理模式

代理模式应用场景

  1. 日志的采集
  2. 权限控制
  3. 实现aop
  4. Mybatis mapper
  5. Spring的事务
  6. 全局捕获异常
  7. Rpc远程调用接口
  8. 代理数据源

代理模式实现的原理
代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy)
抽象主题角色:可以是接口,也可以是抽象类;
委托类角色:真实主题角色,业务逻辑的具体执行者;
代理类角色:内部含有对真实对象RealSubject的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。

5.1.1 代理模式创建方式

com.mayikt.service.OrderService(接口)

public interface OrderService {
    /**
     * 添加订单数据
     */
    String addOrder(String orderName);
}
com.mayikt.service.impl.OrderServiceImpl
import com.mayikt.service.OrderService;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class OrderServiceImpl implements OrderService {
    @Override
    public String addOrder(String orderName) {
        log.info("<orderName:{}>", orderName);
        return "ok";
    }
}
5.1.2 静态代理

基于接口实现方式
com.mayikt.proxy1.OrderServiceProxy

import com.mayikt.service.OrderService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class OrderServiceProxy implements OrderService {
    private OrderService orderService;

    public OrderServiceProxy(OrderService orderService) {
        this.orderService = orderService;
    }

    @Override
    public String addOrder(String orderName) {
        // 目标方法前后处理操作
        log.info("<目标方法之前执行...>");
        String result = orderService.addOrder(orderName);
        log.info("<目标方法之后执行...>");
        return result;
    }
}

Tses

public static void main(String[] args) {
     OrderServiceProxy orderServiceProxy = new OrderServiceProxy(new OrderServiceImpl());
     String result = orderServiceProxy.addOrder("mayikt");
     System.out.println(result);
 }

基于继承实现方式
com.mayikt.proxy2.OrderServiceProxy

import com.mayikt.service.impl.OrderServiceImpl;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class OrderServiceProxy  extends OrderServiceImpl {
    @Override
    public String addOrder(String orderName) {
        // 目标方法前后处理操作
        log.info("<目标方法之前执行...>");
        String result = super.addOrder(orderName);
        log.info("<目标方法之后执行...>");
        return result;
    }
}

Tses

 public static void main(String[] args) {
    OrderServiceProxy orderServiceProxy = new OrderServiceProxy();
    String result = orderServiceProxy.addOrder("mayikt");
    System.out.println(result);
}
5.1.3 动态代理

动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成 。

JDK动态代理的一般步骤如下:

  1. 创建被代理的接口和类;
  2. 实现InvocationHandler接口,对目标接口中声明的所有方法进行统一处理;
  3. 调用Proxy的静态方法,创建代理类并生成相应的代理对象;

实现原理:利用拦截器机制必须实现InvocationHandler接口中的invoke方法实现对我们的目标方法增强。

5.2 AOP详解

5.2.1 Aop常用术语
  1. 连接点(Join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。类中的哪些方法可以被增强,这些方法就被称作为连接点。
  2. 切点(PointCut): 可以插入增强处理的连接点,实际被增强的方法就称作为切入点
  3. 通知(Advice): AOP 框架中的增强处理,通知描述了切面何时执行以及如何执行增强处理, 实际增强的业务逻辑,该过程就可以称作为通知 前置、后置、环绕通知
  4. 切面(Aspect): 切面是通知和切点的结合。 把通知应用到的过程 就是为切面
  5. 引入(Introduction):允许我们向现有的类添加新的方法或者属性。
  6. 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的代理对象

  1. 连接点 该类中哪些方法需要被增强,这些方法就可以称作连接点
  2. 切点 实际被增强的方法
    2 .通知 在方法前后执行代码
    前置通知 调用方法之前处理…
    后置通知 调用完该方法之后处理
    环绕通知 在我们被代理方法前后执行
    异常通知
    最终通知
    4 .切面 把通知应用到的过程 就是为切面
5.2.2 Aop环境准备
  1. Spring框架一般都是基于AspectJ实现AOP操作

(1)什么是AspectJ
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件,AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作.

  1. 基于AspectJ实现AOP

(1)基于xml配置文件实现
(2)基于注解方式(偏多的)

  1. 在项目工程目录引入AOP依赖

maven依赖

<!-- aspectj支持(切面依赖) -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.9</version>
</dependency>
<dependency>
    <groupId>org.apache.geronimo.bundles</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.8_2</version>
</dependency>
<!-- SpringAOP依赖 -->
 <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>

切入点表达式
具体那个类中的那个方法来实现增强
需要描述 该类中哪些方法是需要被增强-----切入点规则

在这里插入图片描述

语法规范execution( [权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]));
例如:

  1. public.String.com.zhaoli.service.MayiktService.addUser(..) --拦截的是MayiktService类中addUser方法名称 所有参数 返回值String
    2.* com.zhaoli.service.MayiktService.*(..)拦截我们的MayiktService类中的所有方法
    3.* com.zhaoli.service.*.*(..)拦截就是我们 com.mayikt.service.包下的所有的类所有的方法。

//举例1:对com.zhaoli.service.MayiktService类里面的 add() 进行增强 execution(*com.zhaoli.service.MayiktService.add(..)); // * 表示所有, … 表示参数列表
//举例2:对com.zhaoli.service.MayiktService类里面的 所有方法 进行增强 execution(*com.zhaoli.service.MayiktService.*(..));
//举例3:对com.zhaoli.service.MayiktService所有类里面的 所有方法 进行增强 execution(*com.zhaoli.service.MayiktService.*.*(..));

开启springaop
这是配置 spring.xml 的模板可以直接粘贴

<?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
      ">

注意粘贴时将这一段代码替换掉

测试代码(前置通知\后置通知)
com.zhaoli01.service.MayiktService

import org.springframework.stereotype.Component;

@Component //等同于 <bean id="userProxy" class="com.zhaoli01.prox.UserProxy">
public class MayiktService {
    public String addUser() {
        System.out.println("addUser...");
        return "ok";
    }
}

com.zhaoli01.proxy.UserProxy

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component //等同于 <bean id="userProxy" class="com.zhaoli01.prox.UserProxy">
@Aspect //定义切面
public class UserProxy {
    /**
     * //@Before(value="定义切入点") 拦截我们 MayiktService 类中的所有方法
     * 前置通知
     */
    @Before(value = "execution(* com.zhaoli01.service.MayiktService.*(..));")
    public void before() {
        System.out.println("在目标方法之前执行...");
    }

    /**
     * 后置通知
     */
    @After(value = "execution(* com.zhaoli01.service.MayiktService.*(..));")
    public void after() {
        System.out.println("在目标方法之后执行...");
    }
}

Resources\spring_08.xml

<?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.zhaoli01"></context:component-scan>

   <!-- 开启切面 -->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

test`

public static void main(String[] args) {
    ClassPathXmlApplicationContext classPathXmlApplicationContext= new ClassPathXmlApplicationContext("spring_08.xml");
    MayiktService mayiktService = classPathXmlApplicationContext.getBean("mayiktService", MayiktService.class);
    mayiktService.addUser();
}

测试代码(环绕通知)
com.zhaoli01.service.MayiktServiceResources\spring_08.xml 同上
com.zhaoli01.proxy.UserProxy

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component //等同于 <bean id="userProxy" class="com.zhaoli01.prox.UserProxy">
@Aspect //定义切面
public class UserProxy {
    /**
     * //@Before(value="定义切入点") 拦截我们 MayiktService 类中的所有方法
     * 前置通知
     */
    @Before(value = "execution(* com.zhaoli01.service.MayiktService.*(..));")
    public void before() {
        System.out.println("在目标方法之前执行...");
    }

    /**
     * 后置通知
     */
    @After(value = "execution(* com.zhaoli01.service.MayiktService.*(..));")
    public void after() {
        System.out.println("在目标方法之后执行...");
    }

    /**
     * 环绕通知 前置+后置组合
     */
    @Around(value = "execution(* com.zhaoli01.service.MayiktService.*(..));")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知调用目标方法之前...");
        Object result = proceedingJoinPoint.proceed();//调用我们目标方法
        System.out.println("环绕通知调用目标方法之后...");
        return result;
    }
}

返回通知、表达异常通知

//@AfterReturning表达后置通知/返回通知,表达方法返回结果之后执行
    @AfterReturning(value = "execution(* com.mayikt.service.MayiktService.addMayikt(..));")
    public void afterReturning() {
        System.out.println("afterReturning");
    }

    //@AfterThrowing表达异常通知
    @AfterThrowing(value = "execution(* com.mayikt.service.MayiktService.addMayikt(..));")
    public void afterThrowing() {
        System.out.println("afterThrowing");
    }

代码优化

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component //等同于 <bean id="userProxy" class="com.zhaoli01.prox.UserProxy">
@Aspect //定义切面
public class UserProxy {
    /**
     * 定义切入点 用的时候直接调用 减少代码冗余
     */
    @Pointcut(value = "execution(* com.zhaoli01.service.MayiktService.*(..));")
    private void pointcut() {
    }

    /**
     * //@Before(value="定义切入点") 拦截我们 MayiktService 类中的所有方法
     * 前置通知
     */
    @Before(value = "pointcut()")
    public void before() {
        System.out.println("在目标方法之前执行...");
    }

    /**
     * 后置通知
     */
    @After(value = "pointcut()")
    public void after() {
        System.out.println("在目标方法之后执行...");
    }

    /**
     * 环绕通知 前置+后置组合
     */
    @Around(value = "pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知调用目标方法之前...");
        Object result = proceedingJoinPoint.proceed();//调用我们目标方法
        System.out.println("环绕通知调用目标方法之后...");
        return result;
    }
}

spring框架中使用 cglib?jdk动态代理?
spring aop 底层基于代理模式封装
如果我们被代理类 有实现接口的情况下 则使用 jdk动态代理

如果我们 被代理类 没有实现接口的情况下 则使用 cglib动态代理

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

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

相关文章

Python酷库之旅-第三方库Pandas(120)

目录 一、用法精讲 531、pandas.DataFrame.reindex_like方法 531-1、语法 531-2、参数 531-3、功能 531-4、返回值 531-5、说明 531-6、用法 531-6-1、数据准备 531-6-2、代码示例 531-6-3、结果输出 532、pandas.DataFrame.rename方法 532-1、语法 532-2、参数 …

用Python实现时间序列模型实战——Day 23: LSTM 与 RNN 模型的深入学习

一、学习内容 1. 深入理解 LSTM 和 RNN 模型的工作原理 LSTM 和 RNN 模型都擅长处理时间序列数据&#xff0c;但它们在处理长序列时遇到了一些问题&#xff0c;比如 梯度消失 和 梯度爆炸。LSTM 通过 门控机制 改进了传统 RNN 的缺陷&#xff0c;但在处理非常长的序列时仍可能…

Java浅,深拷贝;内,外部类的学习了解

目录 浅拷贝 深拷贝 内部类 匿名内部类 实例内部类 静态内部类 外部类 浅拷贝 简单理解&#xff1a;定义了A&#xff0c;A里面有age和num&#xff0c;拷贝成为B&#xff0c;B里面有age和num package demo1浅克隆和深克隆;//interfaces 是定义了一个接口//implements是使…

火语言RPA流程组件介绍--浏览器页面操作

&#x1f6a9;【组件功能】&#xff1a;浏览器页面前进&#xff0c;后退&#xff0c;刷新及停止等操作 配置预览 配置说明 丨操作类型 后退/前进/刷新 丨超时时间 支持T或# 输入仅支持整型 页面操作超时时间 丨执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待…

Spring框架常见漏洞

文章目录 SpEL注入攻击Spring H2 Database Console未授权访问Spring Security OAuth2远程命令执行漏洞(CVE-2016-4977)Spring WebFlow远程代码执行漏洞(CVE-2017-4971)Spring Data Rest远程命令执行漏洞(CVE-2017-8046)Spring Messaging远程命令执行漏洞(CVE-2018-1270)Spring …

Python酷库之旅-第三方库Pandas(119)

目录 一、用法精讲 526、pandas.DataFrame.head方法 526-1、语法 526-2、参数 526-3、功能 526-4、返回值 526-5、说明 526-6、用法 526-6-1、数据准备 526-6-2、代码示例 526-6-3、结果输出 527、pandas.DataFrame.idxmax方法 527-1、语法 527-2、参数 527-3、…

C语言刷题日记(附详解)(5)

一、选填部分 第一题: 下面代码在64位系统下的输出为( ) void print_array(int arr[]) {int n sizeof(arr) / sizeof(arr[0]);for (int i 0; i < n; i)printf("%d", arr[i]); } int main() {int arr[] { 1,2,3,4,5 };print_array(arr);return 0; } A . 1…

vi | vim基本使用

vim三模式&#xff1a;① 输入模式 ②命令模式 ③末行模式&#xff08;编辑模式&#xff09; vim四模式&#xff1a;① 输入模式 ②命令模式 ③末行模式&#xff08;编辑模式&#xff09; ④V模式 一、命令模式进入输入模式方法&#xff1a; 二、命令模式基…

Hybrid接口的基础配置

Hybrid模式是交换机端口的一种配置模式&#xff0c;它允许端口同时携带多个VLAN&#xff08;虚拟局域网&#xff09;的流量。Hybrid端口可以指定哪些VLAN的数据帧被打上标签&#xff08;tagged&#xff09;和哪些VLAN的数据帧在发送时去除标签&#xff08;untagged&#xff09;…

828华为云征文|部署知识库问答系统 MaxKB

828华为云征文&#xff5c;部署知识库问答系统 MaxKB 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 核心竞争力1.3 计费模式 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 MaxKB3.1 MaxKB 介绍3.2 Docker 环境搭建3.3 MaxKB 部署3.4 Max…

Leetcode—322. 零钱兑换【中等】(memset(dp,0x3f, sizeof(dp))

2024每日刷题&#xff08;159&#xff09; Leetcode—322. 零钱兑换 算法思想 dp实现代码 class Solution { public:int coinChange(vector<int>& coins, int amount) {int m coins.size();int n amount;int dp[m 1][n 1];memset(dp, 0x3f, sizeof(dp));dp[0][…

基于springboot+vue+uniapp的驾校报名小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

使用随机森林模型在digits数据集上执行分类任务

程序功能 使用随机森林模型对digits数据集进行手写数字分类任务。具体步骤如下&#xff1a; 加载数据&#xff1a;从digits数据集中获取手写数字图片的特征和对应的标签。 划分数据&#xff1a;将数据集分为训练集和测试集&#xff0c;测试集占30%。 训练模型&#xff1a;使用…

鸿蒙开发笔记_电商严选02_登录页面跳转到我的页面、并传值

鸿蒙开发笔记整理,方便以后查阅! 由于上班较忙,只能抽空闲暇时间,快速整理更新中。。。 登录页面跳转到我的页面、并传值 效果图 我的设置页面 /*** 我的设置页面*/ import CommonConstants from ./CommonConstants import ItemData from ./ItemData import DataModel fr…

某个图形商标驳回,不建议做驳回复审!

近日一四川的网友联系到普推知产商标老杨&#xff0c;咨询看驳回的商标可以做驳回复审不&#xff0c;是个纯图形商标&#xff0c;这个一看是一标多类&#xff0c;就是在一个商标名称是申请两个类别&#xff0c;42类部分通过&#xff0c;35类全部驳回。 35类和42类引用的近似商标…

07_Python数据类型_集合

Python的基础数据类型 数值类型&#xff1a;整数、浮点数、复数、布尔字符串容器类型&#xff1a;列表、元祖、字典、集合 集合 集合&#xff08;set&#xff09;是Python中一个非常强大的数据类型&#xff0c;它存储的是一组无序且不重复的元素&#xff0c;集合中的元素必须…

SpringBoot 消息队列RabbitMQ死信交换机

介绍 生产者发送消息时指定一个时间&#xff0c;消费者不会立刻收到消息&#xff0c;而是在指定时间之后才收到消息。 死信交换机 当一个队列中的消息满足下列情况之一时&#xff0c;就会成为死信(dead letter) 消费者使用basic.reject或 basic.nack声明消费失败&#xff0…

LidarView之定制版本

介绍 LidarView软件定制开发需要关注几点&#xff1a;1.应用程序名称&#xff1b;2.程序logo&#xff1b;3.Application版本号&#xff1b;4.安装包版本号 应用程序名称 在项目的顶层cmake里边可以指定程序名称 project(LidarView)需要指定跟Superbuild一样的编译类型 set…

英语学习之fruit

目录 不熟悉熟悉 不熟悉 breadfruit 面包果 date 椰枣 raspberry 覆盆子 blackberry 黑莓 blackcurrant 黑加仑&#xff0c;黑醋栗 plum 李子 熟悉 apple 苹果&#x1f34e; coconut 椰子&#x1f965; banana 香蕉&#x1f34c; tomato 西红柿 pear 梨子 watermelon 西瓜…

30款免费好用的工具,打工人必备!

免费工具软件&#xff0c;办公人必备&#xff0c;提升工作效率 启动盘制作&#xff1a;Ventoype工具&#xff1a;微PEwindows/office jh工具&#xff1a;HEU KMS Activator桌面资料转移工具&#xff1a;个人资料专业工具右键菜单管理&#xff1a;ContextMenuManager驱动安装&a…