【Java学习】 Spring的基础理解 IOC、AOP以及事务

这篇具有很好参考价值的文章主要介绍了【Java学习】 Spring的基础理解 IOC、AOP以及事务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

    官网: https://spring.io/projects/spring-framework#overview
    官方下载工具: https://repo.spring.io/release/org/springframework/spring/
    github下载: https://github.com/spring-projects/spring-framework
    maven依赖:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

  1.spring全家桶的结构构图:

        
    最下边的是测试单元   其中spring封装了自己的测试单元
  1.  Core Container

    上边一层(Core Container)是核心容器,也是spring框架的基础 也是核心
  • core:提供了框架的基本组成部分  包括ioc和依赖注入功能
  • beans:提供了BeanFactory  实现了工厂模式。方便解耦
  • context:上下文内容
  • expression:提供了强大的表达式语言,用于在运行时查询和操作对象。

    3.Data Access/Integration 数据访问/集成

  • 该模块包含JDBC、ORM、OXM、JMS和事务处理模块
  • JDBC:提供了JDBC的抽象层,可以更方便的处理数据库
  • ORM:模块提供了流行的对象关系型映射的API的集成
  • OXM:模块提供了对OXM实现的支持(啥是OXM)
  • JMS:包含了生产和消费消息的功能
  • 事务:毋庸置疑,可以实现特殊接口类以及所有的pojo支持编程式和声明式事务管理。

     4.Web

            Web层由Web、Servlet、Web-Sockethe和Web-Portlet组成
  • Web模块:提供面向web的基本功能和面向web的应用上下文
  • Servlet模块:为web应用提供了模型视图看着(MVC)和RestWeb服务的实现。Spring的MVC框架可以将代码与web表单进行分离。
  • Web-Socket
  • Web-Portlet
    5.AOP
            Aop模块提供了面向切面编程的实现,允许自定义放啊拦截器和切入点,对代码继续宁解耦,可以减少模块间的耦合度,方便扩展和提高可维护性
    6.Instrumentation
    7.Messaging
    8.Aspects
            也是面向切面编程
    9.Test

二、IOC:

  2.1理论:IOC也就是控制反转
            其基本理解就是Spring将创建对象的过程转交给了IOC容器。,在其它类中我们只需要调用即可,不需要重新创建对象。
        在我们传统的三层架构模型中,目录结构分别为pojo、dao、和service
    当我们在service中调用dao时,常会使用到
        private UserDao userDao=new UserDao();
    这就是我们通常的思维,需要创建对象才可以使用,但是引入spring后,便可以使用<bean>标签就可以创建对象。
    2.2 Spring 中IOC的实现提供了两种方式:
        2.2.1BeanFactory:这是IOC的基本实现,是Spring的内部接口,不会提供给开发人员使用。
        加载配置文件时,不会创建对象,只有在使用的时候才会创建对象(一会可以代码解释  注意的是getBean的动作)
        2.2.2ApplicationContext 它是BeanFactory接口的子接口,提供了更加强大的功能开发人员进行加载配置文件的时候就进行了创建。
//1.引入jar包

//2.编辑配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
配置对象  id为唯一限定名 一般为类名的小写   class是类所在的位置
    <bean id="teacher" class="com.qiang.pojo.Teacher"></bean>
</beans>

//3.测试
@Test
public void testTeacherCreate(){
    //加载配置文件
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Teacher teacher = ac.getBean("teacher", Teacher.class);
    System.out.println(teacher);
}

//在以上代码中  如果使用的是ApplicationContext 则在进行加载配置文件时 就已经在IOC容器中创建好了teacher对象
//如果是使用的是 BeanFactory ac 创建对象,则在getbean时才会创建对象(不可操作,因为该接口不对开发人员透明)

2.2.3 ApplicationContext接口的实现类的继承关系

【Java学习】 Spring的基础理解 IOC、AOP以及事务

由上图可以看出,我们能使用的只有ClassPathXMlApplicationContext和FileSystemXmlApplicationContext来解析我们的xml配置文件。
其中Class开头的可以去classpath路径下去寻找
File开头的可以加载磁盘路径下的配置文件
之后我们还可以使用AnnotationconfigApplicationContext可以使用注解方式来创建容器。
 
2.3 IOC对Bean的管理
    2.3.1 创建bean
        bean就是我们所说的Java对象,在之前所学的创建Java对象,一般是使用new关键字 调用类中的构造器来创建对象。
    因此创建bean的方法就可以有三种方式:使用默认的无参构造、使用简单工厂方式创建、使用静态工厂方式创建
        A:使用默认的无参构造
<bean id="唯一标识" class="类的全限定名"> </bean>

        B :使用普通工厂类创建bean实例

1.建立普通类teacher,包含个别属性,并添加get、set方法

2.创建工厂类
public class SchoolFactory {
    Teacher teacher=new Teacher();
    public  Teacher getInstance(){
        return teacher;
    }
}
在工厂类中实例化对象,并添加一个普通方法可以获取到对象

3.配置文件

<!--    普通工厂类创建bean实例-->
    <bean id="factory" class="com.qiang.pojo.factory.SchoolFactory" ></bean>
    <bean id="teacher1" factory-bean="factory" factory-method="getInstance"></bean>

第一个bean是一个实例化的对象也就是对象工厂
第二个bean 是利用对象工厂来创建的对象实例化
            factory标签指的是  是哪个工厂对象,对应上边的id
            factory-method指的是调用可以获取对象实例的方法(普通方法)


4.测试:

/**
* 测试普通工厂类创建bean实例
*/
@Test
public void testTeacherFactory1(){
    //加载配置文件
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Teacher teacher1 = ac.getBean("teacher1", Teacher.class);
    System.out.println(teacher1);
}

如果在程序中可能需要频繁的创建某个类的实例对象,采用工厂模式会更好

  2.3.2 依赖注入 也就是注入属性
 
            依赖注入也就是对属性的注入,分为三种:构造器注入、set注入以及p标签注入
            其中的构造注入,需要走的是带参构造
            set注入,走的是set方法和无参构造
            p标签注入和set注入基本一样,只不过头文件中需要引入
 
        对象工厂接口中最基本的是BeanFactory,它可以支持懒加载,也就是在加载配置文件时,不会创建实例对象,而是在需要调用时才会创建。
        如今使用的是applicationContext来解析配置文件,他的底层接口也是BeanFactory,但是它可以在加载配置文件的时候,就直接创建了bean实例。
 
 
        以Student类作为演示
public class Student {
    private String sname;
    private int age;
    private String sex;


    public Student(String sname, int age, String sex) {
        this.sname = sname;
        this.age = age;
        this.sex = sex;
        System.out.println("这是三个参数的无参构造");
    }


    public Student(String sname, int age) {
        this.sname = sname;
        this.age = age;
        System.out.println("这是第一个属性为name的两个参数的构造");
    }
    public Student( int age,String sname) {
        this.sname = sname;
        this.age = age;
        System.out.println("这是第一个属性为age的两个参数的构造");


    }


    public Student() {
        System.out.println("这是无参构造");
    }




    public String getSname() {
        return sname;
    }


    public void setSname(String sname) {
        this.sname = sname;
    }


    public int getAge() {
        return age;
    }


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


    public String getSex() {
        return sex;
    }


    public void setSex(String sex) {
        this.sex = sex;
    }


    @Override
    public String toString() {
        return "Student{" +
                "sname='" + sname + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
  A 构造器注入 <constructor-arg>
<bean id="stu1" class="com.qiang.pojo.Student">
    <constructor-arg name="sname" value="zs"></constructor-arg>
    <constructor-arg name="age" value="15"></constructor-arg>
</bean>
看我们的实体类中就可以发现,我们的含有两个参数的构造器,有两个,在这个时候我们使用的构造器的构造函数就不知道使用的是哪个带参的构造器
因此我们可以使用 index来标识下标 就可以指定先执行那个代餐的构造

    其中constructor-arg中也可以使用type来标识参数类型来确定属性
        如果是八大基本数据类型,则可以直接写关键字,如果是其他类型,则需要添加类的全限定路径

    如果其中还含有其他对象类型的参数,
    如此时的student类中包含属性  private Grade grade;
    
    构造器:
        <bean>
        <construct-arg type="com.qiang.Grade" ref="grade"></construct-arg>
        </bean>
            
        <bean id="grade" class="com.qiang.Grade"></bean>

   B set方法注入  此时需要在类中对属性添加set方法 以及无参构造

<bean id="student2" class="com.qiang.pojo.Student">
        <property name="id" value="2"></property>
        <property name="name" value="李四"></property>
    </bean>

    C :p标签注入 此时就要添加对应的set方法以及无参构造 以及添加头文件

    D:也可以set注入和构造器注入 混合使用 但是需要有对应的构造方法

  2.3.3   不同属性类型对应的写法:
        由于我们的属性的在不同的使用场景下可能有不同的属性类型,如集合、数组等情况,因此可能会需要使用到不同的标签,下面只演示使用set方法注入的情况 那就意味着,我们需要添加构造方法和无参构造。
实体类
public class Order {
    private String [] cources;
    private List<String> lists;
    private Map<String,String> maps;
    private Set<String> sets;
配置文件

<!--    测试不同属性类型的属性注入-->
    <bean id="order" class="com.qiang.pojo.Order">
<!--        数组集合使用array标签-->
        <property name="cources">
            <array>
                <value>美羊羊</value>
                <value>兰羊羊</value>
            </array>
        </property>
<!--        list集合类型使用list标签-->
        <property name="lists">
            <list>
                <value>舒克</value>
                <value>贝塔</value>
            </list>
        </property>
<!--        set集合使用set标签-->
        <property name="sets">
            <set>
                <value>mysql</value>
                <value>javase</value>
                <value>javaweb</value>
            </set>
        </property>


        <property name="maps">
            <map>
                <entry key="java" value="我们在学习的语言"></entry>
                <entry key="web" value="前端的"></entry>
            </map>
        </property>
数组类型的使用<array><value></value></array>
    list类表类型的使用:<list><value></value></list>
    set集合类型的使用<set><value></value></set>
    map集合类型的使用<map><entry key="" value=""></entry></map>
 
2.4 Bean的作用域: scope属性
  • singleton:默认值  单例模式 每次获取的bean都是同一个对象
  • prototype:每次获取bean都会被重新实例化
  • request:每次请求都会重新实例化对象,但是在同一请求下获取的情况下的bean是单例的
  • session  每次会话内的bean是单例的
  • application:整个应用程序对象内的bean实例都是单例模式的
  • websocket:同一个websocket对象内的对象是单例的。
Singleton
<!--    测试单例模式-->
    <bean id="stu3" class="com.qiang.pojo.Student" scope="singleton"></bean>

测试类:

@Test
public void testStudent3(){
    //加载配置文件
    BeanFactory ac=new ClassPathXmlApplicationContext("applicationConfig2.xml");
    Student stu1 = ac.getBean("stu3", Student.class);
    System.out.println(stu1);
    Student stu2 = ac.getBean("stu3", Student.class);
    System.out.println(stu2);
    System.out.println(stu1==stu2);
}

结果:
com.qiang.pojo.Student@10a035a0
com.qiang.pojo.Student@10a035a0
true
prototype

<!--    测试多例模式-->
<bean id="stu4" class="com.qiang.pojo.Student" scope="prototype"></bean>

测试类

@Test
public void testStudent4(){
    //加载配置文件
    BeanFactory ac=new ClassPathXmlApplicationContext("applicationConfig2.xml");
    Student stu1 = ac.getBean("stu4", Student.class);
    System.out.println(stu1);
    Student stu2 = ac.getBean("stu4", Student.class);
    System.out.println(stu2);
    System.out.println(stu1==stu2);
}

结果:
com.qiang.pojo.Student@10a035a0
com.qiang.pojo.Student@67b467e9
false
2.5  bean的生命周期
     2.5.1 一般理解下的bean的生命周期:
  • 通过构造器创建bean实【此时执行的是无参构造】
  • 为bean属性设置值以及对其他的bean的引用【set注入】
  • 调用bean的初始化方法,在配置文件中配置
  • bean对象可以使用了 【已经获取到了对象】
  • 当容器关闭时,调用bean的销毁方法【在配置文件中配置】
实体类对象
public class People implements Serializable {
    private String oid;
    public People() {
        System.out.println("第一步:执行无参构造");
    }
    public String getOid() {
        return oid;
    }
    public void setOid(String oid) {
        this.oid = oid;
        System.out.println("第二步: 调用set方法给属性设置值......");
    }
    public void initMethod(){
        System.out.println("第三步:执行初始化方法............");
    }
    public void destroyMethod(){
        System.out.println("第五步:执行销毁方法............");
    }
    @Override
    public String toString() {
        return "People{" +
                "oid='" + oid + '\'' +
                '}';
    }
}
配置文件  添加初始化方法 和销毁方法
<bean id="people" class="com.qiang.pojo.People" 
    init-method="initMethod" 
    destroy-method="destroyMethod">
</bean>
其中的标签init-method、destroy-method 中的方法是在实体类中自定义的

 测试类

/**
* 测试bean的生命周期
*/
@Test
public void testBeanLive(){
    //加载配置文件
    ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig2.xml");
    //获取bean实例
    People people = ac.getBean("people", People.class);
    System.out.println("第四步:获取bean实例对象 。。。");
    System.out.println(people);
    //手动销毁
    ac.close();
}



结果:
第一步:执行无参构造
第三步:执行初始化方法............
第四步:获取bean实例对象 。。。
People{oid='null'}
第五步:执行销毁方法............

 文章来源地址https://www.toymoban.com/news/detail-488611.html

  2.5.2 添加后置处理器的生命周期的方法
  • 第一步:执行无参数的构造方法 。。。
  • 第二步: 调用set方法给属性设置值......
  • 在初始化之前执行的方法
  • 第三步:执行初始化方法............
  • 在初始化之后执行的方法
  • 第四步:获取bean实例对象 。。。
  • 第五步:执行销毁方法............

 

在实体类中 实现了BeanPostProcessor接口
    并重写了
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("在初始化之前执行的方法");
    return bean;
}


@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("在初始化之后执行的方法");


    return bean;
}

 

  2.6 自动装配:
    装配的意思是 就是怎么去创建对象
spring的装配方式有三种:
        在xml中显示的装配 也就是使用<bean>标签
        在Java中的显示配置 new关键字
        自动装配机制
 
        Spring的自动装配你有两个角度的实现
            分别是 组件扫描和 自动装配
                组件扫描:spring 回自动发现应用上下文中所创建的bean
                自动装配:spring自动满足bean之间的依赖,也就是使用IOC和DI
     自动装配的实现方式有两种,一种是通过xml的bena标签 也可以使用注解方式
        2.6.1  通过XMl中的标签 自动装配
    
    A:byName 按名称自动装配
        通俗理解:在xml配置文件中 使用bean标签 通过bynae自动诸如和,每次遇到名称为 byname属性值时就自动创建对象
实体类Dog
private String color;
private int age;


配置文件
<bean id="d1" class="com.qiang.pojo.Dog" autowire="byName">
    <property name="age" value="15"></property>
</bean>

测试类:
@Test
public void testDog1(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Dog d1 = ac.getBean("d1", Dog.class);
    System.out.println(d1.getAge());
}

结果:
15

  B.byType 按类型自动装配

配置文件
<bean id="d1" class="com.qiang.pojo.Dog" autowire="byType">
    <property name="age" value="21"></property>
</bean>


测试类:
@Test
public void testDog1(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Dog d1 = ac.getBean(Dog.class);
    System.out.println(d1.getAge());
}


结果:
21

 

2.6.2根据注解开发
            spring中的注解注入的有:@Autowired、@Resources @Qualifier   @Service @Commonent @Controller  @Repository
    在使用注解开发时,需要现在配置文件中开启组件扫描功能
<!--开启组件扫描-->
    <context:component-scan base-package="cn.liushao"></context:component-scan>
 
开启组件扫描  便可以自动查找其中的自动注入
    不同的注解的区分:
  • Autowired是自动注入,自动从spring的上下文找到合适的bean来注入。
  • Resource用来指定名称注入。
  • Qualifier和Autowired配合使用,指定bean的名称。
  • Service,Controller,Repository分别标记类是Service层类,Controller层类,Dao层的类,spring扫描注解配置时,会标记这些类要生成bean。
  • Component是一种泛指,标记类是组件,spring扫描注解配置时,会标记这些类要生成bean。
@Autowired注解
    默认按类型装配springbean 默认情况下,必须要求依赖对象必须存在。如果容器中有多个相同类型的bean,则框架会抛出异常。
    @Qualifier
    此注解用来消除依赖注入冲突的。我们可以消除需要注入那个bean的问题
    通过该注解,我们可以使用特定的Spring Bean一起装配,Spring框架可以从多个相同类型并满足装配要求的bean中找到我们想要的。
    @Resource是按名称装配:

 

分析:  由于注解@Autowired是默认按类型装配的,一个类型的可能会有多个实现方法
        因此在演示的时候 就可以选择一个接口,有多个实现类来作为演示

1.构建一个接口
public interface TeacherService {
    public void sayName();
    public void saysex();
}


2.创建多个实现类(以三个举例)
@Component
public class TeacherServiceImpl1 implements TeacherService {
    @Override
    public void sayName() {
        System.out.println("A");
    }
}

@Component
public class TeacherServiceImpl1 implements TeacherService {
    @Override
    public void sayName() {
        System.out.println("B");
    }
}

@Component
public class TeacherServiceImpl1 implements TeacherService {
    @Override
    public void sayName() {
        System.out.println("C");
    }
}

3.创建两外一个类,可以调用该类的实现类
public class TeacherController {
    @Autowired
    //创建对象
    private TeacherService teacherService;
    public void soutResult(){
        teacherService.sayName();
    }
}

4.修改配置文件 开启扫描

<!--    测试注解开发-->
    <context:component-scan base-package="com.qiang"></context:component-scan>

5.测试:

@Test
public void testAopAno(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    TeacherController contro = ac.getBean("teacherController", TeacherController.class);
    contro.soutResult();
}
6.观察结果:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'teacherController': Unsatisfied dependency expressed through field 'teacherService'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.qiang.service.TeacherService' available: expected single matching bean but found 3: teacherServiceImpl1,teacherServiceImpl2,teacherServiceImpl3

分析:由于在service接口有多个实现类,使用autowired是按类型注入,可能会找不到使用哪个  因此可以搭配使用@Qualifier注解


修改第三步:
public class TeacherController {
    @Autowired
    @Qualifier("teacherServiceImpl1")
    //创建对象
    private TeacherService teacherService;
    public void soutResult(){
        teacherService.sayName();
    }
}
继续进行测试  结果为:
A
结果显示正常


继续修改第三步:
public class TeacherController {
   @Resource(name = "teacherServiceImpl1")
    //创建对象
    private TeacherService teacherService;
    public void soutResult(){
        teacherService.sayName();
    }
}
继续进行测试  结果为:
A
结果显示正常

 

通过上述例子可以看出,如果一个类需要由多个实例变量时,可以搭配使用 @Autowired
    @Qualifier("teacherServiceImpl1"),也可以单独使用 @Resource(name = "teacherServiceImpl1"

 

三、AOP
 
    3.1AOP简介:
        AOP通俗理解就是面向切面编程,是对面向对象的一种补充、将那些与业务无关的,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模板,这个模板就被称为”切面“,使用AOP减少了系统中的重复代码、降低了模块间的耦合度,同时提高了系统的可维护性。
    AOP的底层是动态代理,分别为JDK动态代理和CGLIB动态代理
 
    3.2术语:
        连接点:可以被增强的方法
        
        切入点: 实际真正被增强的方法,称为切入点
 
        通知(增强):又被叫做增强,实际增强的逻辑部分称为通知[增强]
 
        切面(是个动作):把通知应用到切入点的过程。
 
其中:通知有五种:
        前置通知(before) 后置(返回)通知(after returning) 、环绕通知(Around)、异常通知(after-throwing)
 
通知通俗理解就是AOP暴漏给我们的方法,我们在这个方法中直接定义需要扩展的代码即可,但是其执行顺序,交给了spring来处理。
 
 
        3.3 AOP的准备工作:
首先介绍一下Aspect J  这个是一个独立的AOP模型,但不是Spring框架的内容。
    因此在演示的时候需要导入相关的jar包,或者使用maven文件
 
 
    切入点表达式:知道对那个类的方法进行增强
        execution( [权限修饰符] [返回值类型] [类的全路径] [方法名][参数列表])
 
    3.4 AOP通知
        3.4.1基于XML的配置通知
    A 第一种方式:
1.添加jar包

2.建造实体类和代理对象类
    普通类应包含一个普通方法,该普通方法也就是要增强的那个方法
public class Student implements Serializable {
    public void add(){
        System.out.println("这个只是一个普通的方法");
    }
}


public class StudentProxy {
    //配置前置通知
    public void before(){
        System.out.println("前置通知。。。。。");
    }
    //配置后置返回通知
    public void afterreturning(){
        System.out.println("后置返回通知....");
    }
    //配置最终通知
    public void after(){
        System.out.println("最终通知....");
    }
    //配置环绕通知
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知前");
        proceedingJoinPoint.proceed();
        System.out.println("环绕通知后....");
    }
    //配置异常通知
    public void afterThrow(){
        System.out.println("异常通知....");
    }
}



3.修改配置文件


在修改配置文件时应注意,头文件也需要进行修改

xmlns:aop="http://www.springframework.org/schema/aop"
xsi:http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd"

//注入
<bean id="student" class="com.qiang.pojo.Student"></bean>
<bean id="studentProxy" class="com.qiang.pojo.StudentProxy"></bean>

<aop:config >
    <!--切入点-->
    <aop:pointcut id="pc" expression="execution(* com.qiang.pojo.Student.add(..))"/>
    <!--配置切面-->
    <aop:aspect ref="studentProxy">
        <!--将增强应用到具体的方法上-->
        <!--前置通知-->
        <aop:before method="before" pointcut-ref="pc"></aop:before>
        <!--后置返回通知-->
       <aop:after-returning method="afterreturning" pointcut-ref="pc"></aop:after-returning>
        <!--最终通知-->
        <aop:after method="after" pointcut-ref="pc"></aop:after>
        <!--环绕通知-->
        <aop:around method="around" pointcut-ref="pc"></aop:around>
    </aop:aspect>
以上没有演示异常通知,异常通知在程序发生异常时才会发生。


测试:
@Test
public void testAopXmlDemo1(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig.xml");
    Student student = ac.getBean("student", Student.class);
    student.add();
}



结果:

前置通知。。。。。
环绕通知前
这个只是一个普通的方法
环绕通知后....
最终通知....
后置返回通知....
分析:
    前置通知:在连接点之前执行的通知
    后置返回通知:一般在方法的结尾,必然会多一个返回值
    环绕通知:包含了前置通知和后置通知
    异常通知:处理异常数据,事务回滚
    
3.4.2基于注解的配置通知
    B:第二种方式
1.引入jar包
 
2.创建实体类
@Component
public class User {
    public void add(){
        System.out.println("这是一个普通方法");
    }
}

3.创建代理类
@Component
@Aspect //生成代理对象
public class UserProxy {
    //前置通知
    @Before(value = "execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void before(){
        System.out.println("前置通知。。。");
    }
    //后置返回通知
    @AfterReturning(value = "execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void afterReturning(){
        System.out.println("后置返回通知afterReturning....");
    }
    //环绕通知
    @Around(value = "execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕之前....");
        // 被增强的方法执行了
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后....");
    }
//    //异常通知 只有手动创造了异常才可以触发这个通知
//    @AfterThrowing(value = "execution(* org.qiang.aop.anno.pojo.User.add(..))")
//    public void afterThrowing(){
//        System.out.println("异常通知 afterThrowing......");
//    }


//最终通知
    @After(value = "execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void after(){
        System.out.println("最终通知....");
    }

}

//修改配置文件


<!--    开启组件扫描-->
    <context:component-scan base-package="org.qiang.aop.anno"></context:component-scan>


<!--    开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


//测试:

@Test
public void testAopAnno(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationConfig2.xml");
    User user = ac.getBean("user", User.class);
    user.add();
}



结果:
环绕之前....
前置通知。。。
这是一个普通方法
环绕之后....
最终通知....
后置返回通知afterReturning....

    C:第三种方式抽取重复代码

只需要修改代理类对象就可以了
@Component
@Aspect //生成代理对象
public class UserProxy {




//    抽取切入点
    @Pointcut(value = "execution(* org.qiang.aop.anno.pojo.User.add(..))")
    public void pointcutDemo(){


    }
    //前置通知
    @Before(value = "pointcutDemo()")
    public void before(){
        System.out.println("前置通知。。。");
    }
   
   
    //后置返回通知
    @AfterReturning(value = "pointcutDemo()")
    public void afterReturning(){
        System.out.println("后置返回通知afterReturning....");
    }
   
   
    //环绕通知
    @Around(value = "pointcutDemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕之前....");
        // 被增强的方法执行了
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后....");
    }
    
    
//    //异常通知 只有手动创造了异常才可以触发这个通知
//    @AfterThrowing(value = "pointcutDemo()")
//    public void afterThrowing(){
//        System.out.println("异常通知 afterThrowing......");
//    }


    
    
    //最终通知
    @After(value = "pointcutDemo()")
    public void after(){
        System.out.println("最终通知....");
    }
    
}
  D :  AOP 底层是动态代理默认的是JDK动态代理的方法,也可以通过
    <aop: aspectj-autoproxy proxy-target-class="true"></aop :aspect-autoproxy>
标签来修改,其默认值是false是JDK动态代理的格式,改为true就可以使用CGLIB代理格式。

 

3.5 Spring的事务管理
 
    Spring框架将固定的冗余部分的套路代码进行了封装,对程序员仅提供简单的XML配置就可以完成事务的管理,不需要在编写事务管理代码。这也就是Spring的非常重要功能--声明式事务
    
    声明式事务是基于AOP实现的(动态代理)。程序员只需要调用持久层代码和业务逻辑代码,将开启事务的代码反正该了前置通知中,将事务回滚和事务提交的代码放在了后置通知中。
 
 
    使用事物可以保证操作前后数据的完整性,事务的四个特性:ACID 原子性、一致性、隔离性和持久性
 
 
    编程式事务:整个事务的操作都是由程序员进行手动管理,手动提交,手动回滚
    声明式事务:整个事务由其他框架进行管理,我们使用事务的时候只需要进行简单的声明或
                        者配置即可。
 
 
    Spring中的Tx模块就包含了对声明式事务的封装,以下是我们的日常的手动提交事务的写法:
public void testdemo1() throws SQLException {
    Connection conn= DriverManager.getConnection("","","");
    //关闭自动提交
    conn.setAutoCommit(false);
    try {
        PreparedStatement ptst=conn.prepareStatement("insert into bank  values=(?,?)");
        
        ptst.executeUpdate();
        
    }catch (Exception e){
    //再发生异常时,就会进行事务的回滚
        conn.rollback();
    }
    
}
   回顾Aop切面编程,可以发现共通点,在关闭自动提交的部分,可以用前置通知来代替,try代码块的部分就可以理解为是切入点,事务提交的部分可以使用后置通知来实现,而对于出现异常,事务回滚的操作就可以使用异常通知来处理。
也就是:
在org.springframework.jdbc.datasource.DataSourceTransactionManager 中的
方法:
protected void doBegin(){
    conn.setAutoCommit(false)
}

protected void doBegin() {

}

protected void doRollback() {


}

 

添加事务通知:

<tx:advice id="tt" transaction-manager="transactionmanager">
    <tx:attributes>
            <tx: method name="方法名">
    </tx:attributes>
</ tx: advice>


<aop:config>
              <aop:pointcut id="pt"  expression="execution(* 类的全路径.方法(. .))" />
            <aop:advisor advice-ref="tt"  pointcut-ref="pt"> </aop:advisor>
</aop:config>

 

 

声明式事务的四个基础属性介绍:
        <tx:method>标签下有属性配置,也可以用在注解上:

 

 

 

 

 

 

 

 

到了这里,关于【Java学习】 Spring的基础理解 IOC、AOP以及事务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring IOC 与 AOP 基础原理,一篇搞定

    控制反转,一切对象交给Spring来创建于管理,将创建与使用对象的代码进行分离作用。实现代码的解耦。 因为以前的对象创建都是在程序的创建,管理。这是所谓的正转,如今的对象的创建是在IOC中,在 IOC Container中获取。这就是反转。 DI,denpendecy inject。依赖注入,在应用

    2024年01月21日
    浏览(40)
  • 【Java面试】Spring中的IOC和AOP

    IOC:控制反转也叫依赖注入。利用了工厂模式 将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的

    2024年02月10日
    浏览(50)
  • IDEA项目实践——Spring框架简介,以及IOC注解

    IDEA创建项目的操作步骤以及在虚拟机里面创建Scala的项目简单介绍 IDEA项目实践——创建Java项目以及创建Maven项目案例、使用数据库连接池创建项目简介 IDEWA项目实践——mybatis的一些基本原理以及案例 IDEA项目实践——动态SQL、关系映射、注解开发 文章目录 第1章 Spring 概述

    2024年02月14日
    浏览(48)
  • 深入了解 Spring boot的事务管理机制:掌握 Spring 事务的几种传播行为、隔离级别和回滚机制,理解 AOP 在事务管理中的应用

    🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 《Spring 狂野之旅:从入门到入魔》 🚀 本专栏带你从Spring入门到入魔   这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.csdn

    2024年03月21日
    浏览(83)
  • 【面试题】谈谈你对IOC和AOP的理解

    IoC(Inverse of Control:控制反转)是一种设计思想,就是将 原本在程序中手动创建对象的控制权,交由Spring框架来管理 。IOC思想是基于IOC容器来完成的,IOC容器底层就是对象工厂(BeanFactory接口)。IOC的原理是基于xml解析、工厂设计模式、反射来实现的。 IoC 容器实际上就是个

    2024年02月05日
    浏览(79)
  • Spring IOC & AOP

    IOC,全程Inversion of Control(控制反转) 通过控制反转(创建对象的权限交给框架,所以叫反转)创建的对象被称为 Spring Bean ,这个Bean和用new创建出来的对象是没有任何区别的。 官方解释:Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖

    2024年02月16日
    浏览(39)
  • Spring核心思想之IOC和AOP

    IOC和AOP不是Spring提出的,在spring之前就已经存在,只不过更偏向于理论化,Spring在技术层次把这两个思想做了⾮常好的实现(Java)。 什么是IoC? IoC Inversion of Control (控制反转/反转控制),注意它是⼀个 技术思想 ,不是⼀个技术实现。 描述的事情 :Java开发领域对象的创建,

    2024年02月09日
    浏览(55)
  • spring的AOP和IOC的原理

    目录 一、spring的ioc与aop原理 二、代理模式: 三、静态代理 四、动态代理 五、实际的操作 六、动态代理的实现: 七、什么是AOP 八、主流的AOP框架: 九、术语: 十、通知的五种类型: 十一、AOP的优点: 十二、AOP开发流程 核心概念:控制反转(IOC)/(DI),面向切面(AO

    2024年02月05日
    浏览(45)
  • spring框架,以及和spring框架相关的Java面试题和spring ioc的注入方式

    目录 一.spring来源,以及介绍 1.spring诞生的背景 2.spring框架 介绍 3.spring框架在使用中的优点以及不足 3.1优点  3.2不足 3.3总结 4.为什么要使用spring  二.将spring框架部署在IDEA中  1.替换pom.xml  2.构建spring所需要的xml文件 三.spring的三种注入方式 0.定义需要的类,方法 1.方法注入

    2024年02月12日
    浏览(51)
  • 深入解析Spring的IOC与AOP及其在项目中的应用

    在现代的软件开发中,为了提高代码的可维护性、可扩展性以及降低代码的耦合度,使用设计模式和面向切面编程(AOP)成为了程序员们常用的技术手段。Spring作为一个优秀的Java开发框架,提供了IOC和AOP两个核心特性,极大地简化了开发工作。本文将深入探讨Spring的IOC和AO

    2024年02月13日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包