• Spring


    目录

    1.Spring概述

    1.1.什么是Spring

    EE开发分成三层结构

    1.2.为什么学习Spring

    1.3.http://localhost:1111/spring-basic.html - spring的版本Spring的版本

    1.4.spring功能模块划分

     2、JAVA类的耦合与解耦

    2.1.什么是程序的耦合

    2.2.解决耦合的思路

    2.2.1.工厂模式解耦

    2.2.2.控制反转-Inversion Of Control

    3.Spring的 IOC

    3.1.什么是IoC

    3.2.IoC的作用

    3.3.基于XML的IoC配置入门

    3.4.ApplicationContext

    4. Bean的配置

    4.1.spring中的bean元素相关配置Spring中的bean元素相关配置

    4.1.1.id属性和name属性

    4.1.2.scope属性

    4.1.3.生命周期属性

    4.2.Spring生成Bean的时候的三种方式

    4.3.Spring中Bean属性的注入

    4.3.1.方式1:构造方法的方式注入属性

    4.3.2.方式2:set方法的方式注入属性

    4.4.在配置文件中引入Properties配置

    4.5.复杂类型的注入

    ​编辑4.6.Spring的分配置文件开发

    5.Spring注解方式的Bean管理

    5.1.Spring Bean管理中的常用注解

    5.1.1.准备工作

    5.1.2.@Component

    5.1.3.属性注入的注解@Value、@Autowired

    5.1.4.Bean的作用范围的注解

    5.1.5.Bean的生命周期的配置

    6.AOP的概述

    6.1.什么是AOP

    6.2.为什么学习AOP

    6.3.Spring的AOP的由来

    6.4.底层实现

    7.Spring AOP基于XML实现

    7.1.AOP开发中的相关术语

    7.2.基于XML配置方式声明切面

    7.2.1.pom依赖

    7.2.2.写切面类

    7.2.3.被代理的业务类

    7.2.4.配置aop切面

    8.Spring AOP基于Annotation实现

    8.1.基于注解方式声明切面

    8.1.1.pom依赖

    8.1.2.启动@Aspect注解的支持和注解的扫描机制

    8.1.3.写切面类

    8.1.4.写一个业务类(被代理的类)

    8.1.5.测试类


    1.Spring概述

    1.1.什么是Spring

    spring (由Rod Johnson创建的一个开源框架)
    Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003年兴起的-一个轻量级的Java开发框架,由Rod Johnson创建。简单来说,Spring是一个分。层的JavaSE/EE full-stack(- 站式)轻量级开源框架。

    Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作 Expert One-On-One J2EE Development and Design 中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为J2EE应用程序开发提供集成的框架。Spring使用基本的 JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。 Spring的 核心是控制反转(IoC)和面向切面(AOP) 。简单来说, Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。

    EE开发分成三层结构

    • WEB层: Spring MVC
    • 业务层: Bean管理:(IOC)
    • 持久层: Spring的JDBC模板。ORM模板用于整合其他的持久层框架

    Expert One-to-One J2EE Design and Development : J2EE 的设计和开发:(2002.EJB)
    Expert One-to-One J2EE Development without EJB : J2EE 不使用EJB的开发

    1.2.为什么学习Spring

    1、方便解耦,简化开发
            Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
    2、AOP编程的支持
            Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
    3、声明式事务的支持
            只需要通过配置就可以完成对事务的管理,而无需手动编程
    4、方便程序的测试
            Spring对Junit4支持,可以通过注解方便的测试Spring程序
    5、方便集成各种优秀框架
            Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
    6、降低JavaEE API的使用难度
            Spring对JavaEE开发中非常难用的一些API(如:JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

    1.3.http://localhost:1111/spring-basic.html - spring的版本Spring的版本

    Spring3.X 和 Spring4.X 和 Spring5.X

    1.4.spring功能模块划分

     2、JAVA类的耦合与解耦

    2.1.什么是程序的耦合

    在开发中可能会写很多的类,而有些类之间不可避免的产生依赖关系,这种依赖关系称之为耦合
    有些依赖关系是必须的,有些依赖关系可以通过优化代码来解除的。

    1. public class CustomerServiceImpl implements CustomerService {
    2.     CustomerDao customerDao =new CustomerDaoImpl();
    3. }

    以上的代码表示:业务层调用持久层,并且此时业务层在依赖持久层的接口和实现类。如果此时没有持久层实现类,编译将不能通过。这种依赖关系就是我们可以通过优化代码解决的。 
    还有如下面的代码:
    我们的类依赖了MySQL的具体驱动类,如果这时候因为某些原因数据库的品牌从MySQL改为Oracle,那么需要通过改源码来修改数据库驱动。这显然不是我们想要的。

    1. public class JdbcDemo01{
    2.     public static void main(String[] args) throws Exception {
    3.         Class.forName("com.mysql.jdbc.Driver");
    4.         //new com.mysql.jdbc.Driver()
    5.     }
    6. }

    2.2.解决耦合的思路

    当是我们学习JDBC时,是通过反射来注册驱动的,代码如下:
    Class.forName("com.mysql.jdbc.Driver");
    这时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除mysql的驱动jar包,依然可以编译。但是因为没有驱动类,所以不能运行。
    不过,此处也有个问题,就是我们反射类对象的全限定类名字符串是在java类中写死的,一旦要改还是要修改源码。
    解决这个问题也很简单,使用配置文件配置。

    2.2.1.工厂模式解耦

    在实际开发中我们可以把所有的dao和service和controller对象使用配置文件配置起来,当启动服务器应用加载的时候,通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。

    2.2.2.控制反转-Inversion Of Control

    上面解耦的思路有2个问题:
    1、存哪去?
            分析:由于我们是很多对象,肯定要找个集合来存。这时候有Map和List供选择。
            到底选Map还是List就看我们有没有查找需求。有查找需求,选Map。
            在应用加载时,创建一个Map,用于存放controller,Service和dao对象。
            我们把这个map称之为容器。
    2、还是没解释什么是工厂?
            工厂就是负责给我们从容器中获取指定对象的类。这时候我们获取对象的方式发生了改变。
            原来:我们在获取对象时,都是采用new的方式。是主动的。

            现在:我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的。

            这种被动接收的方式获取对象的思想就是控制反转,它是spring框架的核心之一。
            它的作用只有一个:削减计算机程序的耦合。

    3.Spring的 IOC

    3.1.什么是IoC

    Inversion of Control:控制权的转移,创建对象的权利由应用程序转移到容器称为控制反转

    3.2.IoC的作用

    削减计算机程序的耦合(解除我们代码中的依赖关系)

    3.3.基于XML的IoC配置入门

    创建Maven项目,resources 创建spring配置文件

     pom.xml依赖

    1. <dependency>
    2.     <groupId>org.springframework</groupId>
    3.     <artifactId>spring-context</artifactId>
    4.     <version>5.3.8</version>
    5. </dependency>

    编写UserService类

    1. public class UserService {
    2. public UserService() {
    3. System.out.println("调用了UserService的构造方法");
    4. }
    5. public void add() {
    6. System.out.println("调用了UserService的add方法");
    7. }
    8. public void init() {
    9. System.out.println("调用了UserService的init方法");
    10. }
    11. public void destroy() {
    12. System.out.println("调用了UserService的destroy方法");
    13. }
    14. }

    编写applicationContext.xml配置文件

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <!--Spring通过xml配置bean的方式来创建指定对象并管理起来容器-->
    6. <!--<bean> 作用告诉Spring创建对象并管理, id唯一标识, class指定类的全限定名(类名+包名)-->
    7. <!--spring通过反射创建对象-->
    8. <!--<bean id="userService" name="aaa" class="com.tjetc.service.UserService"></bean>-->
    9. <bean id="userService" class="com.tjetc.service.UserService"></bean>
    10. </beans>

    编写测试类Test

    1. package com.tjetc;
    2. import com.tjetc.service.UserService;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class Test {
    5. public static void main(String[] args) {
    6. //创建ClassPathXmlApplicationContext对象, 参数就是定义spring的配置文件
    7. //new ClassPathXmlApplicationContext成功之后,UserService配置的类已经被实例化了
    8. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    9. //通过context的getBean方法获取UserService对象
    10. UserService userService = context.getBean(UserService.class);
    11. //通过配置的id名称获取UserService对象
    12. UserService userService1 = (UserService) context.getBean("userService");
    13. // UserService userService1 =(UserService) context.getBean("aaa");
    14. //调用UserService的add方法
    15. userService.add();
    16. userService1.add();
    17. System.out.println(userService == userService1);//true
    18. }
    19. }

    结果:

    3.4.ApplicationContext

    ApplicatioContext接口有两个基本的实现类:

    ClassPathXmlApplicationContext : 加载类路径下的Spring配置文件。
    FileSystemXmlApplicationContext : 加载本地磁盘下的Spring配置文件。

    4. Bean的配置

    4.1.spring中的bean元素相关配置Spring中的bean元素相关配置

    配置文件中的bean元素用于描述需要Spring容器管理的对象。其 class属性用于指被管理对象的完整类名。

    4.1.1.id属性和name属性

    id属性 

    是为Spring容器管理的对象起个名字。其使用ID约束:

    • 唯一
    • 必须以字母开始
    • 可以使用字母、数字、连字符、下划线、句号、冒号。但 不能出现特殊字符

    name属性 
    也是为被Spring容器管理的对象起个名字。这样后续可以通过该名字从容器中获取对象。
    没有ID中的那些约束(可以重复[不推荐]、可以出现特殊字符)
    如果<bean>没有id的话,name可以当做id使用
    举例

    1. <bean id="bookAction">
    2. <bean name="/loginAction" > 
    3. <bean id="userService" name="aaa" class="com.tjetc.service.UserService">

     此处的名称中由于有特殊字符,只能使用name属性。
    结论:在定义bean的时候,推荐使用name属性来为bean指定名称

    4.1.2.scope属性

    用于声明bean在Spring容器中的作用范围。其取值包括:
    singleton : 默认值  单例的;默认在Spring容器启动的时候就会创建该实例。
    prototype : 多例的;默认在从Spring容器中获取bean时才会创建该实例。
    request : WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中。
    session : WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中。
    globalSession : WEB项目中,应用在Porlet环境。如果没有Porlet环境,那么globalSession相当于session。

    singleton案例

    applicationContext.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <!-- scope="singleton" 是单例,容器启动创建配置的对象,context.getBean对候从容器中获取对象,每次getBean都是同一个对象-->
    6. <bean id="userService" class="com.tjetc.service.UserService" scope="singleton"></bean>
    7. </beans>

    测试类:

    1. import com.tjetc.service.UserService;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. public class TestTest {
    4. public static void main(String[] args) {
    5. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    6. //<bean>的配置项 scope="prototype" context.getBean时候创建对象,每次getBean都是新对象
    7. UserService userService1 = context.getBean(UserService.class);
    8. UserService userService2 = context.getBean(UserService.class);
    9. //==判断两个对象的地址是否相等
    10. System.out.println(userService1 == userService2);
    11. }
    12. }

    prototype案例

    测试类没有改变,只是修改application.xml的配置,运行结果也会有不同

    1. <!-- scope= "prototype" 是多例,容器启动 不创建配置的对象,context.getBean时候创建对象,每次getBean都是新对象-->
    2. <bean id="userService" scope="prototype" class="com.tjetc.service.UserService"></bean>

     

    4.1.3.生命周期属性

    在bean被创建的时候,需要执行一些初始化的逻辑。可以指定bean中的一个方法为其初始化方法。这样Spring在创建完该对象之后,立即调用一下该初始化方法。

    在bean对象销毁的时候,需要执行一些销毁逻辑。可以指定bean中的一个方法为其销毁方法。这样Spring容器在关闭之前并且销毁该对象的时候,会调用一下该销毁方法。

    注意,此处的销毁方法必须是在容器正常关闭(即执行close方法)时,才会被执行。

    init和destroy案例

    applicationContext.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <!--init-method 配置的对象创建成功之后, 会触发init-method配置的方法-->
    6. <!--destroy-method 配置的对象创建成功之后, 会触发destroy-method配置的方法-->
    7. <bean id="userService" class="com.tjetc.service.UserService" scope="singleton"
    8. init-method="init" destroy-method="destroy"></bean>
    9. </beans>

    测试类:

    1. import com.tjetc.service.UserService;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. public class TestTest {
    4. public static void main(String[] args) {
    5. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    6. UserService userService = context.getBean(UserService.class);
    7. userService.add();
    8. //正常关闭
    9. context.close();
    10. }
    11. }

     

    4.2.Spring生成Bean的时候的三种方式

    方式1:无参数的构造方法的方式

    <bean id="userService" class="com.tjetc.service.UserService" scope="singleton" init-method="init" destroy-method="destroy"></bean>

    方式2:静态工厂实例化的方式

    1. import com.tjetc.service.UserService;
    2. public class UserServiceFactory {
    3. public static UserService getBean() {
    4. //这里可以写很复杂的逻辑, 模拟业务
    5. return new UserService();
    6. }
    7. }
    1. <!--class配置的是工厂类,
    2. factory-method配置的是工厂类的静态方法,
    3. 让Spring调用工厂类的静态方法生产对象并管理-->
    4. <bean id="userService2" init-method="init" class="com.tjetc.factory.UserServiceFactory"
    5. factory-method="getBean"></bean>

    测试类:

    1. import com.tjetc.service.UserService;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. public class Test12 {
    4. public static void main(String[] args) {
    5. //创建Spring的上下文对象[调用了UserService的构造方法]
    6. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    7. //通过id值获取bean对象然后强转为UserService
    8. UserService userService2 = (UserService) context.getBean("userService2");
    9. //[调用了UserService的add方法]
    10. userService2.add();
    11. }
    12. }

     

    方式3:实例工厂实例化的方式

    1. import com.tjetc.service.UserService;
    2. public class UserServiceFactory2 {
    3. /**
    4. * 实例方法,要调用次方法,必领先创建UserServiceFactory2的实例对象
    5. *
    6. * @return
    7. */
    8. public UserService getBean2() {
    9. return new UserService();
    10. }
    11. }
    1. <!--配置创建UserServiceFactory2的工厂实例对象并管理-->
    2. <bean id="userServiceFactory2" class="com.tjetc.factory.UserServiceFactory2"></bean>
    3. <!--配置调用UserServiceFactory2的工厂实例对象的getBean2的实例对象接收UserService对象并管理-->
    4. <bean id="userService3" factory-bean="userServiceFactory2" factory-method="getBean2"></bean>

    测试类:

    1. import com.tjetc.factory.UserServiceFactory2;
    2. import com.tjetc.service.UserService;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class Test12 {
    5. public static void main(String[] args) {
    6. //创建Spring的上下文对象[调用了两次UserService的构造方法, 因为配置了两次,id="userService2",id="userService3"]
    7. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    8. //获取工厂bean
    9. UserServiceFactory2 userServiceFactory2 = (UserServiceFactory2) context.getBean("userServiceFactory2");
    10. System.out.println(userServiceFactory2);
    11. //获取UserServiceBean
    12. UserService userService3 = (UserService) context.getBean("userService3");
    13. userService3.add();
    14. UserService userService33 = (UserService) context.getBean("userService3");
    15. //true,bean 单例 在配置,getBean多次也是一个对象
    16. System.out.println(userService3 == userService33);
    17. context.close();
    18. }
    19. }

    4.3.Spring中Bean属性的注入

    4.3.1.方式1:构造方法的方式注入属性

    定义Car

    1. public class Car {
    2. private String name;
    3. private int price;
    4. /**
    5. * 原则上 自定义了有参的构造方法, 最好加一个无参的构造方法, 防止容器启动调用构造方法出现问题
    6. */
    7. public Car() {
    8. }
    9. public Car(String name, int price) {
    10. this.name = name;
    11. this.price = price;
    12. }
    13. public String getName() {
    14. return name;
    15. }
    16. public void setName(String name) {
    17. this.name = name;
    18. }
    19. public int getPrice() {
    20. return price;
    21. }
    22. public void setPrice(int price) {
    23. this.price = price;
    24. }
    25. @Override
    26. public String toString() {
    27. return "Car{" +
    28. "name='" + name + '\'' +
    29. ", price=" + price +
    30. '}';
    31. }
    32. }

    Spring配置Car

    1. <!--配置Car调用对应的构造方法-->
    2. <bean id="car" class="com.tjetc.entity.Car">
    3. <!--配置构造方法参数-->
    4. <constructor-arg name="name" value="保时捷"></constructor-arg>
    5. <constructor-arg name="price" value="1000000"></constructor-arg>
    6. </bean>

    测试

    1. import com.tjetc.entity.Car;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. public class Test12 {
    4. public static void main(String[] args) {
    5. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    6. //通过类型获取bean
    7. Car car = context.getBean(Car.class);
    8. System.out.println(car);
    9. }
    10. }

     

    4.3.2.方式2:set方法的方式注入属性

    基本类型的属性注入

    Spring配置

    1. <!--简单类型属性注入-->
    2. <!--调用无参的构造方法-->
    3. <bean id="car1" class="com.tjetc.entity.Car">
    4. <!--使用属性设置值的前提条件:对应的类的属性要有set方法-->
    5. <property name="name" value="本田"></property>
    6. <property name="price" value="300000"></property>
    7. </bean>

    测试

    1. import com.tjetc.entity.Car;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. public class Test12 {
    4. public static void main(String[] args) {
    5. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
    6. Car car1 = (Car) context.getBean("car1");
    7. System.out.println(car1);
    8. }
    9. }

     

    对象类型的属性注入
    定义Person

    1. package com.tjetc.entity;
    2. public class Person {
    3. private String name;
    4. private Car car;//自定义的Car类型
    5. public Person() {
    6. }
    7. public Person(String name, Car car) {
    8. this.name = name;
    9. this.car = car;
    10. }
    11. public String getName() {
    12. return name;
    13. }
    14. public void setName(String name) {
    15. this.name = name;
    16. }
    17. public Car getCar() {
    18. return car;
    19. }
    20. public void setCar(Car car) {
    21. this.car = car;
    22. }
    23. @Override
    24. public String toString() {
    25. return "Person{" +
    26. "name='" + name + '\'' +
    27. ", car=" + car +
    28. '}';
    29. }
    30. }

    Spring配置

    1. <!--复杂类型属性注入-->
    2. <bean id="person" class="com.tjetc.entity.Person">
    3. <property name="name" value="Jack"></property>
    4. <!-- 复杂类型, 使用ref来引用已经配置的bean的id值-->
    5. <property name="car" ref="car1"></property>
    6. </bean>

    测试:

    1. import com.tjetc.entity.Person;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. public class Test12 {
    4. public static void main(String[] args) {
    5. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
    6. Person person = (Person) context.getBean("person");
    7. System.out.println(person);
    8. }
    9. }

    4.4.在配置文件中引入Properties配置

    db.properties

    1. jdbc.driverName=com.mysql.cj.jdbc.Driver
    2. jdbc.url=jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    3. jdbc.username=root
    4. jdbc.password=123456

    方案1:配置Spring的Bean PropertySourcesPlaceholderConfigurer

    1. <!--读取properties配置文件-->
    2. <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    3. <property name="locations">
    4. <array>
    5. <value>classpath*:db.properties</value>
    6. </array>
    7. </property>
    8. </bean>
    9. <!--配置DbConfiguration, 使用使用属性注入法取到的properties 文件内容-->
    10. <bean id="dbConfiguration" class="com.tjetc.common.DbConfiguration">
    11. <!--${} 读取properties配置的key对应的值数据-->
    12. <property name="driverName" value="${jdbc.driverName}"></property>
    13. <property name="url" value="${jdbc.url}"></property>
    14. <property name="username" value="${jdbc.username}"></property>
    15. <property name="password" value="${jdbc.password}"></property>
    16. </bean>

    方案2:引入 context名称空间 。使用context中提供的 <context:property-placeholder> 指定它的 location 属性值,如果有多个文件,使用 逗号 分割。

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/context
    8. https://www.springframework.org/schema/context/spring-context.xsd">
    9. <!--<context:property-placeholder>引入并读取properties文件内容-->
    10. <context:property-placeholder location="classpath*:db.properties"></context:property-placeholder>
    11. <!--配置DbConfiguration, 使用使用属性注入法取到的properties 文件内容-->
    12. <bean id="dbConfiguration" class="com.tjetc.common.DbConfiguration">
    13. <!--${} 读取properties配置的key对应的值数据-->
    14. <property name="driverName" value="${jdbc.driverName}"></property>
    15. <property name="url" value="${jdbc.url}"></property>
    16. <property name="username" value="${jdbc.username}"></property>
    17. <property name="password" value="${jdbc.password}"></property>
    18. </bean>
    19. </beans>
    1. public class Test12 {
    2. public static void main(String[] args) {
    3. // ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml,applicationContext.xml");
    4. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
    5. DbConfiguration dbConfiguration = (DbConfiguration) context.getBean("dbConfiguration");
    6. System.out.println(dbConfiguration);
    7. }
    8. }

     classpath:xx 这种写法,只会搜索到文件夹类型的下面的资源。不会搜索到jar包中的。 classpath*:xx 这种写法,都会搜索到。所以【推荐用这种】

    4.5.复杂类型的注入

    定义CollectionDemo

    1. import java.util.Arrays;
    2. import java.util.List;
    3. import java.util.Map;
    4. import java.util.Properties;
    5. public class CollectionDemo {
    6. private String[] strs;
    7. private List<String> list;
    8. private Map<String,String> map;
    9. private Properties properties;
    10. public String[] getStrs() {
    11. return strs;
    12. }
    13. public void setStrs(String[] strs) {
    14. this.strs = strs;
    15. }
    16. public List<String> getList() {
    17. return list;
    18. }
    19. public void setList(List<String> list) {
    20. this.list = list;
    21. }
    22. public Map<String, String> getMap() {
    23. return map;
    24. }
    25. public void setMap(Map<String, String> map) {
    26. this.map = map;
    27. }
    28. public Properties getProperties() {
    29. return properties;
    30. }
    31. public void setProperties(Properties properties) {
    32. this.properties = properties;
    33. }
    34. @Override
    35. public String toString() {
    36. return "CollectionDemo{" +
    37. "strs=" + Arrays.toString(strs) +
    38. ", list=" + list +
    39. ", map=" + map +
    40. ", properties=" + properties +
    41. '}';
    42. }
    43. }

    Spring配置

    1. <bean id="collectionDemo" class="com.tjetc.entity.CollectionDemo">
    2. <!--数组类型的属性注入-->
    3. <property name="strs">
    4. <array>
    5. <value>张三</value>
    6. <value>李四</value>
    7. </array>
    8. </property>
    9. <!--集合类型的属性注入-->
    10. <property name="list">
    11. <list>
    12. <value>123</value>
    13. <value>456</value>
    14. </list>
    15. </property>
    16. <!--Map类型的属性注入-->
    17. <property name="map">
    18. <map>
    19. <entry key="username" value="bxbx"></entry>
    20. <entry key="password" value="9595"></entry>
    21. </map>
    22. </property>
    23. <!--properties类型的属性注入-->
    24. <property name="properties">
    25. <props>
    26. <prop key="xiao"></prop>
    27. <prop key="wang"></prop>
    28. </props>
    29. </property>
    30. </bean>

    测试

    1. import com.tjetc.entity.CollectionDemo;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. public class Test12 {
    4. public static void main(String[] args) {
    5. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
    6. CollectionDemo collectionDemo = (CollectionDemo) context.getBean("collectionDemo");
    7. System.out.println(collectionDemo);
    8. }
    9. }


    4.6.Spring的分配置文件开发

    随着项目越来越大,Spring的配置文件的内容也会越来越多。在实际的开发中,会将不同的配置定义在不同的xml文件中。有两种使用方式:
            方式1:在创建容器的时候加载多个配置文件
            ApplicationContext applicationContext = new                 ClassPathXmlApplicationContext("applicationContext.xml","propertiesContext.xml");
            方式2:在主配置文件中包含其它配置文件(推荐使用)
            <!-- 主配置文件applicationContext.xml中引入子配置文件 -->

            <import resource="propertiesContext.xml"></import>

    propertiesContext.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/context
    8. https://www.springframework.org/schema/context/spring-context.xsd">
    9. <!--读取properties配置文件-->
    10. <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    11. <property name="locations">
    12. <array>
    13. <value>classpath*:db.properties</value>
    14. </array>
    15. </property>
    16. </bean>
    17. <!--<context:property-placeholder>引入并读取properties文件内容-->
    18. <!-- <context:property-placeholder location="classpath*:db.properties"></context:property-placeholder>-->
    19. </beans>

    applicationContext.xml

    1. <!--引入其他的配置文件, 读取其它配置文件内容-->
    2. <import resource="propertiesContext.xml"></import>
    3. <!--配置DbConfiguration, 使用使用属性注入法取到的properties 文件内容-->
    4. <bean id="dbConfiguration" class="com.tjetc.common.DbConfiguration">
    5. <!--${} 读取properties配置的key对应的值数据-->
    6. <property name="driverName" value="${jdbc.driverName}"></property>
    7. <property name="url" value="${jdbc.url}"></property>
    8. <property name="username" value="${jdbc.username}"></property>
    9. <property name="password" value="${jdbc.password}"></property>
    10. </bean>

    test 

    1. import com.tjetc.common.DbConfiguration;
    2. import org.springframework.context.support.ClassPathXmlApplicationContext;
    3. public class Test12 {
    4. public static void main(String[] args) {
    5. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
    6. DbConfiguration dbConfiguration = (DbConfiguration) context.getBean("dbConfiguration");
    7. System.out.println(dbConfiguration);
    8. }
    9. }

    5.Spring注解方式的Bean管理

    主要解决的问题,在XML中一个一个对bean进行配置,开发效率也不高。
    目的:

    • 自动发现哪些对象需要让Spring进行管理,自动将其注册到Spring容器中。
    • 自动注入bean依赖的内容。

    5.1.Spring Bean管理中的常用注解

    5.1.1.准备工作

    使用注解要先开启注解扫描的功能

    1. <!--配置组件的扫描com.tjetc本包及其子孙包下的所有的在类上标注有@Controller,@Service,@Repository,@Component注解的类,
    2. spring会把标注了这些注解的类当做你配置bean节点一样纳入spring容器管理-->
    3. <context:component-scan base-package="com.tjetc"></context:component-scan>

    5.1.2.@Component

    标注在类上,说明这是一个Spring组件。Spring中目前还提供了与 @Component 功能一致的其它三个衍生注解:

    1. @Controller :WEB 层(控制层)
    2. @Service :业务层
    3. @Repository :持久层

            衍生的三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强
    作用和XML配置文件的<bean>标签的实现功能一致;

    5.1.3.属性注入的注解@Value、@Autowired

    使用注解注入的方式,可以不用提供set方法。
    相关注解
    @Value : 用于注入普通类型和String类型。
            加在成员变量上——原理是反射赋值(破坏封装)
            加在set方法上——原理是方法调用(推荐使用)
            它可以使用spring中的spEL(也就是spring的el表达式),SpEl的写法:${表达式}
    @Value使用

    1. package com.tjetc.common;
    2. import org.springframework.beans.factory.annotation.Value;
    3. import org.springframework.stereotype.Component;
    4. @Component("adminConstant")//小括号字符串是AdminConstant类的bean的名称
    5. public class AdminConstant {
    6. //@Value可以把配置数据注入到成员变量或者set×××方法, 前提条件:Spring要对类实例化并管理
    7. //@value 通过${} 读取key对应的value数据
    8. @Value("${img.base.path}")
    9. private String basePath;
    10. private String baseType;
    11. @Value("111111")
    12. private String abc;
    13. @Value("${img.base.type}")
    14. public void setBaseType(String baseType) {
    15. this.baseType = baseType;
    16. }
    17. public String getBasePath() {
    18. return basePath;
    19. }
    20. public void setBasePath(String basePath) {
    21. this.basePath = basePath;
    22. }
    23. public String getBaseType() {
    24. return baseType;
    25. }
    26. @Override
    27. public String toString() {
    28. return "AdminConstant{" +
    29. "basePath='" + basePath + '\'' +
    30. ", baseType='" + baseType + '\'' +
    31. ", abc='" + abc + '\'' +
    32. '}';
    33. }
    34. }

    applicationContext.xml配置

    1. <!--读取properties类型的配置文件-->
    2. <context:property-placeholder location="classpath*:admin.properties"></context:property-placeholder>

    admin.properties

    1. img.base.path=c:/image
    2. img.base.type=jpg,jpeg,gif,png

    测试

    1. package com.tjetc;
    2. import com.tjetc.common.AdminConstant;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class Test12 {
    5. public static void main(String[] args) {
    6. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
    7. AdminConstant adminConstant = (AdminConstant) context.getBean("adminConstant");
    8. System.out.println(adminConstant);
    9. }
    10. }


    @Autowired : 用于注入对象类型(自动装配)
            默认按类型进行装配
            按名称注入: @Qualifier——强制使用名称注入,一般不能单独使用和Autowired配合使用,当注入的对象类型有多个时,@Autowoired必须与@Qualifier一起使用

    @Resource : 相当于@Autowired和@Qualifier一起使用

     UserController.java

    1. package com.tjetc.controller;
    2. import com.tjetc.service.UserService;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.beans.factory.annotation.Qualifier;
    5. import org.springframework.stereotype.Controller;
    6. import javax.annotation.Resource;
    7. @Controller
    8. public class UserController {
    9. // @Autowired 按照类型从spring容器中查找到UserService的bean, 注入到成员变量
    10. // 依赖查找: 根据类型或者bean的名称, 在spring容器中查找相应类型的bean
    11. // 依赖注入: 根据依赖查找到的bean对象, 赋值到指定的成员变量或者set方法
    12. // 按照类型注入存在一个问题: spring容器里有很多个类型相同, 但不是同一个对象的bean, 按照类型注入会报错
    13. // @Autowired
    14. // @Qualifier ----强制使用名称注入, 一般不能单独使用, 要和Autowired配合使用
    15. // @Qualifier("userService1")
    16. // @Resource = @Autowired + Qualifier
    17. @Resource(name = "userService1")//依赖查找并注入,会拿到新的,打印构造方法和初始化
    18. // @Resource(name = "userService2")//单例, 不会打印出init, 单例体现在getBean(),不体现在配置上
    19. private UserService userService;
    20. /**
    21. * 添加
    22. */
    23. public void add() {
    24. /**
    25. * 调用UserService的add方法
    26. */
    27. userService.add();
    28. }
    29. }

     

    applicationContext.xml配置

    1. <!--配置UserService对应的bean--><!--测试有两个不同对象但类型相同的bean-->
    2. <bean id="userService2" class="com.tjetc.service.UserService"></bean>

    5.1.4.Bean的作用范围的注解

    注解@Scope

    • singleton : 单例
    • prototype : 多例

    5.1.5.Bean的生命周期的配置

    相关注解

    • @PostConstruct : 相当于 init-method
    • @PreDestroy : 相当于 destroy-method

    测试

    1. package com.tjetc.service;
    2. import org.springframework.context.annotation.Scope;
    3. import org.springframework.stereotype.Service;
    4. import javax.annotation.PostConstruct;
    5. import javax.annotation.PreDestroy;
    6. @Service("userService1")
    7. //@Scope("singleton")//单例
    8. @Scope("prototype")//多利
    9. public class UserService {
    10. public UserService() {
    11. System.out.println("调用了UserService的构造方法");
    12. }
    13. public void add() {
    14. System.out.println("调用了UserService的add方法");
    15. }
    16. //@PostConstruct 相当于init-method
    17. @PostConstruct
    18. public void init() {
    19. System.out.println("调用了UserService的init方法");
    20. }
    21. // @PreDestroy 相当于destroy-method
    22. @PreDestroy//要关闭context.close();
    23. public void destroy() {
    24. System.out.println("调用了UserService的destroy方法");
    25. }
    26. }
    1. package com.tjetc;
    2. import com.tjetc.common.AdminConstant;
    3. import com.tjetc.controller.UserController;
    4. import com.tjetc.service.UserService;
    5. import org.springframework.context.support.ClassPathXmlApplicationContext;
    6. public class Test12 {
    7. public static void main(String[] args) {
    8. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
    9. UserService userService1 =(UserService) context.getBean("userService1");
    10. UserService userService2 =(UserService) context.getBean("userService1");
    11. //判断地址是否相等,不等,说明是两个对象,相等说明是一个对象
    12. System.out.println(userService1==userService2);//不加多例为true,加了多例为false
    13. context.close();
    14. }
    15. }

    6.AOP的概述

    Aop思想

    6.1.什么是AOP

    AOP(面向切面编程)
    在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统-维护的-种技术。AOP是OOP的延续,是软件开发中的-个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    Spring是解决实际开发中的一些问题:

    • AOP解决OOP中遇到的一些问题。是OOP的延续和扩展。
    • Spring引入AOP思想来为容器中管理的对象动态生成代理对象。

    6.2.为什么学习AOP

    AOP的常用应用场景

    • 权限校验
    • 日志记录
    • 性能监控
    • 事务控制

    6.3.Spring的AOP的由来

    AOP最早由AOP联盟的组织提出的,制定了一套规范。Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范。

    6.4.底层实现

    Spring的AOP底层用到两种代理机制
    JDK 的动态代理 : 针对实现了接口的类产生代理。
            被代理的类必须要实现接口,才能产生代理对象。如果没有接口将不能使用动态代理技术。
    Cglib 的动态代理 : 针对没有实现接口的类产生代理。应用的是底层的字节码增强的技术生成当前类的子类对象。
            可以对任何 非final声明的 类生成代理。

    7.Spring AOP基于XML实现

    7.1.AOP开发中的相关术语

    Joinpoint(连接点) : 所谓连接点是指 那些被拦截到的点 。在Spring中,这些点指的是方法。
    Pointcut(切入点) : 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
    Advice(通知/增强) : 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。通知分为前置通知、后置 通知、异常通知、最终通知、环绕通知(切面要完成的功能)。
    Aspect(切面) : 是切入点和通知(引介)的结合,即切入点+通知

    7.2.基于XML配置方式声明切面

    7.2.1.pom依赖

    1. <dependency>
    2.     <groupId>org.aspectj</groupId>
    3.     <artifactId>aspectjweaver</artifactId>
    4.     <version>1.9.7</version>
    5. </dependency>

    7.2.2.写切面类

    1. package com.tjetc.aop;
    2. import com.tjetc.common.DbDruidUtils;
    3. import org.aspectj.lang.ProceedingJoinPoint;
    4. /**
    5. * 切面类(自定义的业务增强类)
    6. */
    7. public class XMLTransactionPrint {
    8. public void doBefore() {
    9. //模拟业务
    10. System.out.println("前置通知");
    11. // System.out.println("开启事务");
    12. }
    13. public void doAfterReturning() {
    14. //模拟业务
    15. System.out.println("后置通知");
    16. // System.out.println("提交事务");
    17. }
    18. public void doAfterThrowing() {
    19. //模拟业务
    20. System.out.println("异常通知");
    21. // System.out.println("回滚事务");
    22. }
    23. public void doAfter() {
    24. //模拟业务
    25. System.out.println("最终通知");
    26. // System.out.println("关闭连接");
    27. }
    28. /**
    29. * 环绕通知对应的方法
    30. *
    31. * @param pjp 封装了 执行业务方法的相关信息
    32. * @return
    33. * @throws Throwable
    34. */
    35. public Object doRound(ProceedingJoinPoint pjp) throws Throwable {
    36. try {
    37. // System.out.println("环绕前置通知");
    38. System.out.println("开启事务");
    39. DbDruidUtils.beginTransaction();
    40. //执行业务类的方法
    41. Object result = pjp.proceed();
    42. // System.out.println("环绕后置通知");
    43. System.out.println("提交事务");
    44. DbDruidUtils.commit();
    45. return result;
    46. } catch (Throwable throwable) {
    47. throwable.printStackTrace();
    48. // System.out.println("环绕异常通知");
    49. System.out.println("回滚事务");
    50. DbDruidUtils.rollback();
    51. throw throwable;
    52. } finally {
    53. // System.out.println("环绕最终通知");
    54. System.out.println("关闭连接");
    55. DbDruidUtils.closeConnection();
    56. }
    57. }
    58. }

    7.2.3.被代理的业务类

    1. package com.tjetc.service;
    2. import org.springframework.stereotype.Service;
    3. /**
    4. * 已经存在的业务类, 也就是被代理的目标类
    5. */
    6. @Service
    7. public class PersonService {
    8. public void add() {
    9. System.out.println("调用了PersonService的add方法");
    10. }
    11. public void update() {
    12. //查询
    13. //更新库存 更新库存失败(没有出现异常),主动抛出异常
    14. //添加订单
    15. System.out.println("调用了PersonService的update方法");
    16. }
    17. public void delete() {
    18. System.out.println("调用了PersonService的delete方法");
    19. int i = 1 / 0;
    20. }
    21. }

    7.2.4.配置aop切面

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop
    8. https://www.springframework.org/schema/aop/spring-aop.xsd">
    9. <bean id="xmlTransactionPrint" class="com.tjetc.aop.XMLTransactionPrint"></bean>
    10. <bean id="personService" class="com.tjetc.service.PersonService"></bean>
    11. <!--配置aop-->
    12. <aop:config>
    13. <!--配置切面,切面=切点+通知-->
    14. <aop:aspect ref="xmlTransactionPrint">
    15. <!--配置切点-->
    16. <!--expression execution() 执行 固定-->
    17. <!--从左往右-->
    18. <!-- 第一个星号表示 方法的任何返回类型 包括void-->
    19. <!-- com.tjetc.service表示包-->
    20. <!-- 两个点表示包下直接的类和子孙包下的类, 如果是一个点表示包下直接的类-->
    21. <!-- 第二个星号, 表示任何名称的类-->
    22. <!-- 第三个星号, 表示任何名称的方法。 如add-->
    23. <!-- () 表示参数列表-->
    24. <!-- 小括号内的两个点表示0个或者1个或者多个参数类型-->
    25. <aop:pointcut id="mycut" expression="execution(* com.tjetc.service..*.*(..))"/>
    26. <!--配置通知-->
    27. <!--前置通知, 触发点是在调用业务方法之前被调用, 一定会被触发-->
    28. <!-- method 表示自定义增强的方法-->
    29. <!-- pointcut-ref 表示使用哪个切点-->
    30. <aop:before method="doBefore" pointcut-ref="mycut"></aop:before>
    31. <!-- 后置通知, 触发点是在调用业务方法之后, 不一定被触发, 因为业务方法会出现异常-->
    32. <aop:after-returning method="doAfterReturning" pointcut-ref="mycut"></aop:after-returning>
    33. <!-- 异常通知, 触发点是业务方法出现异常, 不一定被触发, 因为业务方法不一定会出现异常-->
    34. <aop:after-throwing method="doAfterThrowing" pointcut-ref="mycut"></aop:after-throwing>
    35. <!-- 最终通知, 触发点是finally, 一定会被触发-->
    36. <aop:after method="doAfter" pointcut-ref="mycut"></aop:after>
    37. <!--环绕通知-->
    38. <!-- <aop:around method="doRound" pointcut-ref="mycut"></aop:around>-->
    39. </aop:aspect>
    40. </aop:config>
    41. </beans>

    测试类:

    1. package com.tjetc;
    2. import com.tjetc.service.PersonService;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class TestAop {
    5. public static void main(String[] args) {
    6. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContextAop.xml");
    7. PersonService personService = context.getBean(PersonService.class);
    8. personService.add();
    9. System.out.println("=========================");
    10. personService.update();
    11. System.out.println("=========================");
    12. personService.delete();
    13. }
    14. }

    配置通知运行

    环绕通知运行

     

     开启环绕通知配置,注释前置通知、后置通知、异常通知、最终通知,进行测试

    8.Spring AOP基于Annotation实现

    8.1.基于注解方式声明切面

    8.1.1.pom依赖

    1. <dependency>
    2.     <groupId>org.aspectj</groupId>
    3.     <artifactId>aspectjweaver</artifactId>
    4.     <version>1.9.7</version>
    5. </dependency>

    8.1.2.启动@Aspect注解的支持和注解的扫描机制

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xmlns:aop="http://www.springframework.org/schema/aop"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans
    7. http://www.springframework.org/schema/beans/spring-beans.xsd
    8. http://www.springframework.org/schema/context
    9. https://www.springframework.org/schema/context/spring-context.xsd
    10. http://www.springframework.org/schema/aop
    11. https://www.springframework.org/schema/aop/spring-aop.xsd">
    12. <!--注解扫描4大注解 @Controller,@Service,@Repository,@Component 纳入Spring管理-->
    13. <context:component-scan base-package="com.tjetc"></context:component-scan>
    14. <!--开启@Aspect注解的使用-->
    15. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    16. </beans>

    8.1.3.写切面类

    @Aspect声明的类,和普通类一样可以添加属性和方法,还可以包含切入点、通知、引入。
     Pointcut声明: 切入点声明包含两个部分: 
     1.签名:由一个名字和多个参数组成,必须返回void, 如:private void anyMethod(){}
       2.切入点表达式  如:@Pointcut("execution(* com.tjetc.service..*.*(..))")

    1. package com.tjetc.aop;
    2. import org.aspectj.lang.ProceedingJoinPoint;
    3. import org.aspectj.lang.annotation.*;
    4. import org.springframework.stereotype.Component;
    5. /**
    6. * 打开注解关闭环绕测试一次
    7. * 关闭注解打开环绕测试一次
    8. */
    9. @Component //纳入Spring管理
    10. @Aspect //切面类(增强类)
    11. public class AnnotationTransactionPoint {
    12. //定义一个空方法, 要求返回值为void, 作为切入点表达式
    13. // @Pointcut 用来编写切点表达式
    14. @Pointcut("execution(* com.tjetc.service..*.*(..))")
    15. private void anyMethod() {
    16. }
    17. //编写四大通知
    18. //前置通知
    19. // @Before("anyMethod()")//@Before 注解的值 写切点表达式对应的方法名称+(), 引入切点表达式
    20. public void doBefore() {
    21. System.out.println("前置通知");
    22. }
    23. // @AfterReturning("anyMethod()")
    24. public void doAfterReturning() {
    25. System.out.println("后置通知");
    26. }
    27. // @AfterThrowing("anyMethod()")
    28. public void doAfterThrowing() {
    29. System.out.println("异常通知");
    30. }
    31. // @After("anyMethod()")
    32. public void doAfter() {
    33. System.out.println("最终通知");
    34. }
    35. @Around("anyMethod()")
    36. public Object doRound(ProceedingJoinPoint pjp) throws Throwable {
    37. try {
    38. System.out.println("环绕前置通知");
    39. //执行业务方法
    40. Object result = pjp.proceed();
    41. System.out.println("环绕后置通知");
    42. return result;
    43. } catch (Throwable throwable) {
    44. System.out.println("环绕异常通知");
    45. throwable.printStackTrace();
    46. throw throwable;
    47. } finally {
    48. System.out.println("环绕最终通知");
    49. }
    50. }
    51. }

    8.1.4.写一个业务类(被代理的类)

    1. package com.tjetc.service;
    2. import org.springframework.stereotype.Service;
    3. /**
    4. * 已经存在的业务类, 也就是被代理的目标类
    5. */
    6. @Service
    7. public class PersonService {
    8. public void add() {
    9. System.out.println("调用了PersonService的add方法");
    10. }
    11. public void update() {
    12. //查询
    13. //更新库存 更新库存失败(没有出现异常),主动抛出异常
    14. //添加订单
    15. System.out.println("调用了PersonService的update方法");
    16. }
    17. public void delete() {
    18. System.out.println("调用了PersonService的delete方法");
    19. int i = 1 / 0;
    20. }
    21. }

    8.1.5.测试类

    1. package com.tjetc;
    2. import com.tjetc.service.PersonService;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class TestAopForAnnotation {
    5. public static void main(String[] args) {
    6. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContextAopForAnnotation.xml");
    7. PersonService personService = context.getBean(PersonService.class);
    8. personService.add();
    9. System.out.println("=========================");
    10. personService.update();
    11. System.out.println("=========================");
    12. personService.delete();
    13. }
    14. }

    配置环绕

     环绕通知


    开启环绕通知配置,注释前置通知、后置通知、异常通知、最终通知,进行测试

     

  • 相关阅读:
    SSM学习——Rest风格与案例(12)
    【RabbitMQ】——消息应答
    车载网络诊断应如何测试?
    Water 2.6.3 发布,一站式服务治理平台
    ts重点学习143-描述文件声明
    Docker-Docker基本组成和架构
    【无标题】
    LeetCode_54_螺旋矩阵
    文心一言 VS 讯飞星火 VS chatgpt (112)-- 算法导论10.2 3题
    android7.1 外置SD卡三方应用没有读写权限
  • 原文地址:https://blog.csdn.net/weixin_45701868/article/details/125426261