栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring spring(spring笔记狂神)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring spring(spring笔记狂神)

Spring笔记

第一章 Spring概述

1.1 概述1.2 优点1.3 Spring体系结构 第二章 IOC控制反转(重点)

IOC控制反转基本概念2.1 Spring的第一个程序

2.1.1 普通Spring项目创建步骤2.1.2 Maven的pom.xml2.1.3 创建service层2.1.4 创建Spring配置文件beans.xml2.1.5 创建测试类test 2.2 基于XML的DI

2.2.1 set注入(设值注入,掌握)2.2.2 构造注入2.2.3 构造注入创建文件对象2.2.4 引用类型属性自动注入2.2.5 注入空值和特殊符号2.2.6 内部bean2.2.7 级联赋值

方式一方式二 2.2.8 注入数组或集合

2.2.8.1 注入数组2.2.8.2 注入List集合2.2.8.3 注入set集合2.2.8.4 注入Map集合2.2.8.5 在对象中引入list属性 2.3 为什么使用多个配置文件?2.4 基于注解的DI

2.4.1 @Component注解2.4.2 组件扫描器2.4.3 简单类型的属性赋值2.4.4 引用类型的属性赋值2.4.5 JDK注解Resource自动注入(自动注入只支持引用类型) 2.5 xml配置文件和注解的对比2.6 完全注解开发2.7 junit 第三章 AOP面向切面编程

3.1 动态代理

3.1.1 创建service接口和实现类3.1.2 实现InvocationHandler接口3.1.3 测试 3.2 AOP简介3.2 AOP术语3.3 切面的关键要素3.4 AOP的实现3. 5 AspectJ对AOP的实现

3.5.1 AspectJ的通知类型/执行时间3.5.2 切入点表达式3.5.3 AspectJ项目创建步骤3.5.4 @Aspect和前置通知@Before3.5.5 JoinPoint3.5.6 @AfterReturning 后置通知-注解有Returning属性3.5.7 @Around 环绕通知3.5 9 @AfterThrowing异常通知(了解)3.5.9 @After最终通知3.5.10 @Pointcut3.5.11 指定cglib动态代理 第四章 Spring集成MyBatis

4.1 概述4.2 Spring集成MyBatis创建项目的流程

4.2.1 添加maven依赖曾经的mybatis-config模板mybatis-mapper模板4.2.2 新建实体类Student4.2.3 新建Dao接口和sql映射文件(Mapper)4.2.4 新建Mybatis主配置文件4.2.5 新建Service接口和实现类4.2.6 新建spring配置文件

数据源DataSourceSqlSessionFactoryBean类创建dao对象service对象Spring配置文件 4.2.7 jdbc.properties4.2.8 新建测试类 第五章 Spring事务

5.1 关于事务的几个问题

5.1.1 什么是事务?5.1.2 在什么时候想到使用事务?5.1.3 事务应该放到哪里?5.1.4 常规事务怎么处理?5.1.5 常规方法处理事务不足之处5.1.6 怎么解决不足? 5.2 Spring处理事务概述

5.2.1 怎么使用Spring处理事务?5.2.2 怎么说明需要事务的类型?

5.2.2.1 事务的隔离级别:5.2.2.2 事务的超时时间(一般不配置,因为影响的因素太多):5.2.2.3 事务的传播行为(重要) 5.2.3 提交事务,回滚事务的时机?5.2.4 总结Spring事务 5.3 Spring框架处理事务

5.3.1 注解(适合中小项目)5.3.2 xml配置文件(适合大型项目) 5.4 程序举例

5.3.1 创建数据库表5.3.2 添加maven依赖5.3.3 创建实体类5.3.4 创建Dao接口和mapper文件5.3.5 创建mybatis主配置文件5.3.6 创建Service接口和实现类5.3.7 创建spring主配置文件5.3.8 创建测试类5.3.9 自定义异常 第六章 使用AspectJ的AOP配置管理事务

6.1 添加依赖(pom.xml)6.2 applicationContext.xml 第七章 web项目中使用容器对象
序:该文章主要用于复习拓展,总结自动力节点Spring教程,有些地方写的不是很好,感谢各位指正。
(一些地方有摘录和补充)
(动力节点Spring视频教程链接: 动力节点Spring教程链接)

第一章 Spring概述 1.1 概述

Spring:

2002年左右诞生,降低企业级开发难度,帮助进行模块、类与类之间的管理,帮助开发人员创建对象,管理对象之间的关系。
2003年传入国内,被大量使用。
2017出现新的流行框架SpringBoot,核心思想与Spring相同。 核心技术:IoC、AOP,能使模块之间、类之间解耦合。依赖:class A使用class B的属性或方法,称之为class A依赖class B。官网:spring.io 1.2 优点

轻量:Spring的所需要的jar包都非常小,一般1M以下,几百kb。核心功能所需要的jar包总共3M左右。
Spring框架运行占有资源少,运行效率高,不依赖其他jar。针对接口编程,解耦合AOP 编程的支持方便集成各种优秀框架

2,3,4的优点在接下来的学习中体会。

1.3 Spring体系结构

Spring 由 20 多个模块组成,它们可以分为数据访问/集成(Data Access/Integration)、 Web、面向切面编程(AOP, Aspects)、提供JVM的代理 (Instrumentation)、消息发送(Messaging)、 核心容器(Core Container)和测试(Test)。

第二章 IOC控制反转(重点) IOC控制反转基本概念

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做**依赖注入(Dependency Injection,简称DI**),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

(摘自百度百科)

控制反转(IoC,Inversion of Control),是一个概念,一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值, 依赖的管理。

(自己总结)

控制: 创建对象,对象的属性赋值,对象之间的关系管理。

正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。

public static void main(String args[]){
	Student student = new Student(); // 在代码中,创建对象。--正转。
}

反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。

由容器代替开发人员管理对象。创建对象,给属性赋值。

容器:是一个服务器软件, 一个框架(spring)

为什么要使用 ioc:

目的就是减少对代码的改动, 也能实现不同的功能,实现解耦合。

java中创建对象有哪些方式?

构造方法, new反射序列化克隆ioc:容器创建对象动态代理…

ioc的体现:

servlet:

第一步:创建类继承HttpServelt

第二步:在web.xml 注册servlet,使用

myservlet
com.bjpwernode.controller.MyServlet1

第三步:没有创建 Servlet对象,没有 MyServlet myservlet = new MyServlet()

Servlet是Tomcat服务器它能你创建的。Tomcat也称为容器。

Tomcat作为容器,里面存放的有Servlet对象,Listener,Filter对象。

IoC的技术实现:

依赖查找:DL( Dependency Lookup ),容器提供回调接口和上下文环境给组件;依赖注入:DI(Dependency Injection),程序代码不做定位查询,这些工作由容器自行完成。

Spring框架使用依赖注入(DI)实现IOC。DI 是ioc的技术实现。DI:依赖注入,只需要在程序中提供要使用的对象名称就可以,至于对象如何在容器中创建,赋值,查找都由容器内部实现。

IOC底层:

xml解析、工厂模式、反射;

spring是一个容器,管理对象,给属性赋值,底层是反射创建对象。

Spring提供的IOC容器实现的两种方式(两个接口)

BeanFactory接口:IOC容器基本实现是Spring内部接口的使用接口,不提供给开发人员进行使用(加载配置文件时候不会创建对象,在获取对象时才会创建对象)ApplicationContext接口:BeanFactory接口的子接口,提供更多更强大的功能,提供给开发人员使用(加载配置文件时候就会把在配置文件对象进行创建)推荐使用! 2.1 Spring的第一个程序 2.1.1 普通Spring项目创建步骤

第一步:创建空项目 spring第二步:创建模板Module - Maven - Create from archetype - quickstart

Name:ch01-hellospringGroupId:com.bjpowernode 第三步:加入maven依赖

Spring依赖,5.3.15——Maven Repositoryjunit依赖maven-compiler-plugin插件可加可不加(在指定java版本的前提下。) 第四步:创建类(接口和它的实现类)

类要自己写,框架只是帮你创建对象。和没有使用框架一样,就是普通的类。 第五步:创建Spring需要使用的配置文件,声明类的信息,这些类由Spring创建和管理。第六步:测试spring创建的对象。 2.1.2 Maven的pom.xml

重点:单元测试依赖和Spring依赖



  4.0.0

  com.bjpowernode
  ch01-hellospring
  1.0-SNAPSHOT

  
    UTF-8
    1.8
    1.8
  

  
    
    
      junit
      junit
      4.11
      test
    

    
    
      org.springframework
      spring-context
      5.3.15
    

  

  

2.1.3 创建service层
package com.bjpowernode.service;

public interface SomeService {
    void doSome();
}

package com.bjpowernode.service.impl;

import com.bjpowernode.service.SomeService;

public class SomeServiceImpl implements SomeService {
    public SomeServiceImpl(){
        System.out.println("impl的无参构造方法");
    }
    @Override
    public void doSome() {
        System.out.println("执行了doSome方法");
    }
}
2.1.4 创建Spring配置文件beans.xml

如同在Servlet中我们需要在web.xml中注册我们希望服务器自动创建管理的servlet对象一样,在Spring中也需要有类似的配置,来自动创建刚才的SomeServiceImpl对象。

在 src/main/resources/目录现创建一个 xml 文件,文件名可以随意,但 Spring 建议的名称为 applicationContext.xml。 IDEA已经为我们设计好了Spring配置文件的模板;

右击resources–>new–>XML configuration file–>Spring Config

注意,Spring 配置文件中使用的约束文件为 xsd 文件。作用与Mybatis的sql映射文件的dtd约束文件类似,但xsd约束作用更强:
1)定义一个 xml 文档中都有什么元素
2)定义一个 xml 文档中都有什么属性
3)定义一个 xml 文档中元素可以有哪些子元素,以及元素的顺序。
4)定义一个 xml 文档中元素和属性的数据类型。

bean标签的属性:

class:类的全限定名称,不能是接口(Spring使用反射创建对象);class可以是非自定义的对象,例如”java.util.Date“,依然可以被Spring创建对象。id:自定义的对象名称,要求是唯一值。 表示在Spring中的对象名称,通过这个名称可以从Spring中找到对象,获取对象scope:指定bean对象的作用域(对象的存在范围和可见性)。可取值:

单例:singleton,默认值,表示叫这个名称的对象在spring容器中只有一个。原型:prototype,表示每次使用getBean()都创建一个新的对象。




    
    
    
    
    
    



2.1.5 创建测试类test

重点:ApplicationContext表示Spring容器。

package com.bjpowernode;

import com.bjpowernode.service.SomeService;
import com.bjpowernode.service.impl.SomeServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Date;

public class MyTest {
    //测试的注解
    @Test
    public void test01(){
//        SomeService someService = new SomeService() {
//            @Override
//            public void doSome() {
//
//            }
//        }
        SomeService someService = new SomeServiceImpl();
        someService.doSome();
    }

    
    @Test
    public void test02(){
        //使用spring容器创建的对象
        //1. 指定spring配置文件的名称
        String config = "beans.xml";
        //2. 创建表示spring容器的对象,ApplicationContext。
        //ApplicationContext就是表示Spring容器,通过这个容器对象就能获取对象了。
        //ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件。类路径:target/classes
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //3. 从容器中获取某个对象,你要调用对象的方法。
        //从容器Map中获取。
        SomeService someService = (SomeService) ac.getBean("someService");
        //4. 使用spring创建好的对象
        someService.doSome();
    }
    
    
    @Test
    public void test03(){
        //1. 获取配置文件
        String config = "beans.xml";
        //2. 加载配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //使用spring提供的方法,获取容器中定义的对象的数量。
        //definition:定义
        int nums = ac.getBeanDefinitionCount();
        System.out.println(nums);
        //容器中每个对象的名称
        String[] names = ac.getBeanDefinitionNames();
        for (String name :
                names) {
            System.out.println(name);
        }
    }
    
    
    @Test
    public void test04(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        Date mydate = (Date) ac.getBean("mydate");
        System.out.println(mydate);
    }
}

2.2 基于XML的DI

DI:依赖注入,表示创建对象,给属性赋值;

di 的实现语法有两种:

在spring的配置文件中,使用标签和属性完成,叫做基于XML的di实现。使用spring中的注解,完成属性赋值,叫做基于注解的di实现。

di 的语法分类:

set注入(设值注入):spring调用类的set方法,在set方法中实现属性的赋值。

百分之八十使用set注入。

必须有setter方法,否则会报错。

构造注入:spring调用类的有参数构造方法,创建对象。在构造方法中完成赋值。

2.2.1 set注入(设值注入,掌握)

set注入(设值注入):Spring调用类的set方法进行赋值。

简单类型注入


    
    

引用类型注入


	




    
    
        
        
        
        
         
        
        

    
    
    
        
        
        
     

    
        
    

package com.bjpowernode;

import com.bjpowernode.ba01.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Date;

public class MyTest {
    //测试的注解
    @Test
    public void test01(){
        //由于applicationContext.xml文件在ba01目录下,因此从类的根路径开始,还要添加一层目录。
        String config = "ba01/applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取对象
        Student student = (Student) ac.getBean("student");
        System.out.println(student);

        Date date = (Date) ac.getBean("date");
        System.out.println(date);
    }
}

2.2.2 构造注入

构造注入:spring调用类有参构造方法,在创建对象的同时,在构造方法中给属性赋值。

1. 构造注入使用标签;
2. 一个标签代表一个参数,3个参数需要三个标签。
3. 标签属性:
	name:表示构造方法形参名
	index:表示构造方法参数的位置,参数从左往右位置是0, 1, 2...
	value:构造方法的形参是简单类型,使用value
	ref:构造方法是引用类型,使用ref。



    

    
    
        
        
        
    

    
    
        
        
        
    
    
    
    
        
        
        
     

@Test
public void test02(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("ba01/applicationContext.xml");
    Student student = (Student) ac.getBean("student");
    Student student1 = (Student) ac.getBean("student1");
    Student student2 = (Student) ac.getBean("student2");
    System.out.println(student);
    System.out.println(student1);
    System.out.println(student2);
}
2.2.3 构造注入创建文件对象


    
    

@Test
public void test03(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("ba01/applicationContext.xml");
    File myfile = (File) ac.getBean("myfile");
    System.out.println(myfile);
}
2.2.4 引用类型属性自动注入


    
    



    
    




    
    
    

2.2.5 注入空值和特殊符号

    
    
        
    
    
    
     
    
        
            >]]>
        

2.2.6 内部bean

内部bean可以用于:

一对多关系:部门和员工一个部门有多个员工,一个员工属于一个部门(部门是一,员工是多)

    
        
        
        
        
        
            
                
            
        
    
2.2.7 级联赋值 方式一

就是引入外部bean,使用ref。

    
        
        
        
        
        
    
    
        
    
方式二
 //方式二:生成dept的get方法(get方法必须有!!)
    public Dept getDept() {
        return dept;
    }
 
    
        
        
        
        
        
        
    
    
    
2.2.8 注入数组或集合 2.2.8.1 注入数组

    
	
        
    	
        	1
            2
        
    

2.2.8.2 注入List集合

    
	
        
    	
        	1
            2
        
    

2.2.8.3 注入set集合

    
            
                1
                2
            
    

2.2.8.4 注入Map集合

    
	
        
    	
        	
            
        
    

2.2.8.5 在对象中引入list属性

注意:一定要引入util 名称空间



        易筋经
        九阴真经
        九阳神功
    

 
    
        
    
2.3 为什么使用多个配置文件?

多个配置文件的优势

第一,每个文件的大小比一个文件要小很多。效率高。第二,避免多人竞争带来的冲突。

如果你的项目有多个模块(相关的功能在一起),一个模块一个配置文件。

例如,学生考勤模块一个配置文件,学生成绩一个配置文件

多文件的分配方式:

按功能模块,一个模块一个配置文件按类的功能,数据库相关的配置一个文件配置文件, 做事务的功能一个配置文件, 做service功能的一个配置文件等

total.xml




    

    



    
    
    

spring-student.xml




    
        
         
    

    
    
        
        
    

    
    
        
        
    


spring-school.xml




    
        
        
        
    


2.4 基于注解的DI

通过注解完成Java对象的创建,属性赋值。

使用注解的步骤:

第一步:加入maven依赖:spring-context,在加入 spring-context 的同时,会间接加入spring-aop的依赖。

使用注解,必须使用spring-aop依赖。

第二步:在类中加入spring的注解(多个不同功能的注解)

第三步:在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目的位置。

第四步:使用注解创建对象,创建容器ApplicationContext

学习的注解:

@Component@Repository@Service@Controller@Value@Autowired@Resource

通过spring的注解完成java对象的创建,属性,代替xml文件。

2.4.1 @Component注解
package com.bjpowernode.ba01;

import org.springframework.stereotype.Component;


//使用value,指定对象的名称。在注解中,如果只写value,value可以省略不写。
//@Component(value="student")

//省略value——最常用的语法。
//@Component("student")

//不指定对象名称,由Spring提供默认名称:类名的首字母小写。
@Component
public class Student {
    private String name;
    private Integer age;

    public Student(){
        System.out.println("无参数构造方法执行");
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

2.4.2 组件扫描器



    
    
    

    
    
    
    

    
    

    
    

2.4.3 简单类型的属性赋值

简单类型的属性赋值,使用:@Value属性:

value:是String类型,表示简单类型的属性值。 位置:

在属性定义的上面,无需set方法,推荐使用。在set方法的上面。

//这个注解是必须的,为了让Spring配置文件找到这个类。然后创建对象
@Component("student")
public class Student {
    @Value("张飞")
    private String name;
    @Value(value="29")
    private Integer age;
    
    @Value("关羽")
    public void setName(String name){
        this.name = name;
    }
}
2.4.4 引用类型的属性赋值

引用类型的赋值

byType

@Autowired

byName

@Autowired
@Qualifier("name")
    @Autowired
    @Qualifier("mySchool")
    private School school;
2.4.5 JDK注解Resource自动注入(自动注入只支持引用类型)
    //原理:默认是byName,先使用byName自动注入,如果byName赋值失败,再使用byType
	//Spring更建议使用@Autowired和@Qualifier注解。
	//@Resource(name="mySchool")
    @Resource
    private School school;
2.5 xml配置文件和注解的对比

经常修改使用xml配置文件不经常修改使用注解注解方便、快捷、直观xml配置文件繁琐,看不了源代码,但是解耦合。 2.6 完全注解开发

    创建配置类,替代 xml 配置文件;

    @Configuration //作为配置类,替代 xml 配置文件
    @ComponentScan(basePackages = {"com.atguigu"})
    public class SpringConfig {
        
    }
    

    编写测试类。

    @Test
    public void testService2() {
        //加载配置类
        ApplicationContext ac
            = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }
    
2.7 junit

junit:单元测试,一个工具类库,做测试方法使用的。

单元:指定的是方法, 一个类中有很多方法,一个方法称为单元。

使用单元测试

第一步:需要加入junit依赖。


    junit
    junit
    4.11
    test

第二步:创建测试作用的类,叫做测试类,在src/test/java目录中创建类

第三步:创建测试方法

1)public 方法
2)没有返回值 void 
3)方法名称自定义,建议名称是test + 你要测试方法名称
4)方法没有参数
5)方法的上面加入 @Test ,这样的方法是可以单独执行的。 不用使用main方法。
第三章 AOP面向切面编程 3.1 动态代理

jdk动态代理:

使用 jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。

jdk动态代理要求目标类必须实现接口。

cglib动态代理:

第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。子类就是代理对象。

要求目标类不能是final的, 方法也不能是final的。

动态代理的作用:

在目标类源代码不改变的情况下,增加功能;减少代码的重复;专注业务逻辑代码;解耦合,让你的业务功能和日志,事务非业务功能分离。

JDK动态代理实现步骤:

第一步:创建目标类,SomeServiceImpl目标类,给它的doSome,doOther增加输出时间、事务的功能。第二步:创建InvocationHandler接口的实现类,在这个类中实现给目标方法增加功能。

第三步:使用JDK中的类Proxy,创建代理对象,实现创建对象的功能。 3.1.1 创建service接口和实现类

package com.bjpowernode.service;

public interface SomeService {
    void doSome();
    void doOther();
}
package com.bjpowernode.service.impl;

import com.bjpowernode.service.SomeService;
import java.util.Date;



public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {
        System.out.println("doSome执行");
    }

    @Override
    public void doOther() {
        System.out.println("doOther执行");
    }
}

3.1.2 实现InvocationHandler接口
package com.bjpowernode.handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

public class MyInvocationHandler implements InvocationHandler {
    
    private Object target;
    public MyInvocationHandler(Object target){
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //返回值
        Object res = null;
        //只让doOther方法执行额外功能
        String methodName = method.getName();
        if("doOther".equals(methodName)){
            System.out.println(new Date());
            //执行目标类的方法,通过method实现。
            res = method.invoke(target, args);
            System.out.println("执行事务");
        }else{
            res = method.invoke(target, args);
        }
        //返回目标方法的结果
        return res;
    }
}

3.1.3 测试
package com.bjpowernode.test;

import com.bjpowernode.handler.MyInvocationHandler;
import com.bjpowernode.service.SomeService;
import com.bjpowernode.service.impl.SomeServiceImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class MyApp {
    public static void main(String[] args) {
        //使用jdk的Proxy创建代理对象。
        //1. 创建目标对象
        SomeService target = new SomeServiceImpl();
        //2. 创建InvocationHandler
        InvocationHandler handler = new MyInvocationHandler(target);
        //3. 创建代理
        SomeService proxy = (SomeService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(), 
            target.getClass().getInterfaces(), 
            handler);
        //4. 通过代理执行方法,会调用handler中的invoke方法
        //doSome和doOther会被传为method
        proxy.doSome();
        System.out.println("================");
        proxy.doOther();
    }
}

3.2 AOP简介

AOP(Aspect Orient Programming),面向切面编程。

面向切面编程是从动态角度考虑程序运行过程;AOP 底层,就是采用动态代理模式实现的。

Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了, 让开发人员用一种统一的方式,使用动态代理。

Aspect:

切面,给你的目标类增加额外的功能,就是切面。像上面用的日志、事务都是切面。切面的特点:一般都是非业务逻辑,可以独立使用。 Orient:

面向,对着 Programming:

编程

OOP:面向对象编程。

怎么理解面向切面编程?

在分析项目功能时,找出切面;合理的安排切面的执行时间(在目标方法前,还是在目标方法后);合理的安排切面执行的位置,在哪个类,哪个方法执行增强功能。

AOP采用了两种代理:

JDK 的动态代理CGLIB 的动态代理

AOP可以看作动态代理的规范化与标准化。

面向切面编程,就是将交叉业务逻辑封装成切面,利用 AOP 容器的功能将切面织入到 主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、 事务、日志、缓存等。 若不使用 AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样, 会使主业务逻辑变的混杂不清。

例如,转账,在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事 务等交叉业务逻辑,而这些业务逻辑与主业务逻辑间并无直接关系。但它们的代码量所占比重能达到总代码量的一半甚至还多。它们的存在,不仅产生了大量的“冗余”代码,还大大干扰了主业务逻辑—转账。

3.2 AOP术语

切面(Aspect)

切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。把通知应用到切入点的过程。 连接点(JoinPoint)

连接业务方法和切面的位置;类里面哪些方法可以被增强,这些方法就成为连接点。简而言之:某类中的业务方法;连接点一般是1个方法。 切入点(Pointcut)

切入点指声明的一个或多个连接点的集合,实际上被真正增强的方法称为切入点。通过切入点指定一组方法。被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。 目标对象(Target)

目标对象指将要被增强的对象。即包含主业务逻辑的类的对象。上例中的 StudentServiceImpl 的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然,不 被增强,也就无所谓目标不目标了。 通知(Advice)

通知是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。Advice 也叫增强。上例中的 MyInvocationHandler 就可以理解为是一种通知。换个角度来说,通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。简言之:切面功能执行的时间点。

切入点定义切入的位置,通知定义切入的时间。

3.3 切面的关键要素

切面的功能代码,切面干什么切面的执行位置,使用Pointcut表示切面执行的位置切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。 3.4 AOP的实现

aop是动态的一个规范化,一个标准

aop的技术实现框架:

spring:

spring在内部实现了aop规范,能完成面向切面编程(AOP);spring主要在事务处理时使用aop;我们项目开发中很少使用spring的aop实现,因为spring的aop比较笨重。

aspectJ:

一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。aspectJ框架实现aop有两种方式:

使用xml的配置文件 : 配置全局事务使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。 3. 5 AspectJ对AOP的实现 3.5.1 AspectJ的通知类型/执行时间

AspectJ 中常用的通知有五种类型,体现在五个不同的添加在切面的注解:
(1)前置通知
(2)后置通知
(3)环绕通知
(4)异常通知
(5)最终通知

切面的执行时间:

这个执行时间在规范中叫做Advice(通知,增强)在aspectj框架中使用注解表示,也可以使用xml配置文件中的标签

@Before@AfterReturning@Around@AfterThrowing@After

切面执行的位置:

切入点表达式 3.5.2 切入点表达式

切入点表达式原型:

execution(modifiers-pattern? ret-type-pattern
		  declaring-type-pattern? name-pattern(param-pattern)
		  throws-pattern? )
问号前面的变量表示是可选的,可以没有。
modifiers-pattern:修饰符(public/private)
ret-type-pattern:返回值类型
declaring-type-pattern:包名、类名
name-pattern:方法名
param-pattern:参数
throws-pattern:抛出异常

execution(访问权限 **方法返回值** **方法声明(参数)** 异常类型)
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强 
(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )
(3)例子如下:
    例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
		execution(* com.atguigu.dao.BookDao.add(..))
 	例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
		execution(* com.atguigu.dao.BookDao.* (..))
    例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
		execution(* com.atguigu.dao.*.* (..))

*:0至多个字符

…:用在方法的参数中,表示任意多个参数;用在包名后,表示当前包及其子包路径。

+:用在类名后,表示当前类及其子类;用在接口后,表示当前接口及其实现类。

execution(* …service..*(…))
可以表示:
com.service.impl
com.bjpowrnode.service.impl
cn.crm.bjpowernode.service

3.5.3 AspectJ项目创建步骤

为什么使用AOP?

目的是在不改变原来的类的代码的前提下,要完成对该类功能的扩展。

使用AspectJ框架实现AOP的步骤:

第一步:新建maven项目

第二步:加入依赖:

spring依赖aspectJ依赖junit依赖

第三步:创建目标类:接口和它的实现类

要做的是给类中的方法增加功能。

第四步:创建切面类:普通类。

在类的上面加入@Aspect

在类中定义方法,方法就是切面要执行的功能代码

在方法的上面加入aspectj中的通知注解,例如@Before

有需要指定切入点表达式execution()。

第五步:创建spring的配置文件,声明对象,把对象交给容器统一管理。

声明对象可以使用注解或者xml配置文件。

声明目标对象声明切面类对象声明aspectj框架中的自动代理生成器标签。

自动代理生成器:用来完成代理对象的自动创建功能。

第六步:创建测试类,从Spring容器中获取目标对象(实际上是代理对象)

通过代理执行方法,实现aop的功能增强。

3.5.4 @Aspect和前置通知@Before

@Aspect:是aspectj框架中的注解。

作用:表示当前的类是切面类。

切面类:用来给业务方法增加功能的类,在这个类中,有切面的功能代码。

可以在Aspect类中定义方法,方法是实现切面功能的。

@Before:前置通知注解

属性:value,是切入点表达式,表示切面的功能执行的位置。

位置:在方法的上面添加注解。

特点:

在目标方法之前先执行不会改变目标方法的执行结果不会影响目标方法的执行。

前置通知方法的定义要求:

公共方法public

方法没有返回值(void)

方法名称自定义

方法可以有参数,也可以没有参数。

如果有参数,参数不是自定义的,有几个参数类型可以使用。

SomeService接口

public interface SomeService{
    void doSome(String name, Integer age);
}

SomeServiceImpl实现类

public class SomeServiceImpl implements SomeService{
    void doSome(Sring name, Integer age){
        System.out.println("doSome方法执行了!");
    }
}

Aspect切面类

@Aspect
public class MyAspect{
    //当execution找不到时,不会生成代理对象,也不会功能增强。
    
    //完整的@Before
    //@Before表示时间,value表示位置,方法体表示功能。
	//@Before
    //(value = "execution(public void com.bjpowernode.ba01.SomeServiceImpl.doSome(String, Integer))")
    
    //除去访问权限
    //@Before(value = "execution(void com.bjpowernode.ba01.SomeServiceImpl.doSome(String, Integer))")
    
    //@Before(value = "execution(void *..SomeServiceImpl.doSome(String, Integer))")
    
    //@Before(value = "execution(* *..SomeServiceImpl.do*(..))")
    
    //do开头的所有方法
    @Before(value = "execution(* do*(..))")
    public void myBefore(){
        //就是切面要执行的功能代码
        System.out.println("前置通知:在目标方法之前输出执行时间:" + new Date());
    }
}

applicationContext.xml配置文件


    
    
    
    
    
    
	

MyTest01测试类

public class MyTest01{
    @Test
    public void test01(){
        String config = "applicationContext.xml";
        Application ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象(经过aspectj框架的处理,实际上已经是代理对象了。)
        SomeService proxy = (SomeService) ac.getBean("someService");
        //通过代理对象执行方法,增强功能
        proxy.doSome("lisi", 20);
    }
}
3.5.5 JoinPoint
@Aspect
public class MyAspect{
    
    @Before(value = "execution(void *..SomeServiceImpl.doSome(String, Integer))")
    //想获取方法信息,就加入参数JoinPoint
    public void myBefore(JoinPoint jp){
        //获取方法的完整定义
        //void com.bjpowernode.ba01.SomeService.doSome(String, Integer)
        System.out.println("方法的签名:" + jp.getSignature());
        
        //获取方法的名称
        //doSome
        System.out.println("方法的名称:" + jp.getSignature.getName());
        //获取方法的实参,返回Object数组,String是第一个实参,Integer是第二个实参
		Object[] args = jp.getArgs();
        for(Object arg:args){
            //lisi
            //20
            System.out.println(arg);
        }
        //就是切面要执行的功能代码
        System.out.println("前置通知:在目标方法之前输出执行时间:" + new Date());
    }
}
3.5.6 @AfterReturning 后置通知-注解有Returning属性

@AfterReturning 后置通知:

后置通知方法的定义要求:

公共方法public方法没有返回值(void)方法名称自定义方法有参数,推荐使用Object,参数名自定义

属性:

value:切入点表达式returning:自定义变量,表示目标方法的返回值。自定义变量名必须和通知方法的形参名相同。

位置:在方法定义的上面。

特点:

在目标方法之后执行。

能够获取到目标方法的返回值,可以根据返回值做不同的处理功能。

Object res = doOther();

可以修改返回值。

后置通知的执行:

Object res = doOther();
myAfterReturning(res);
@Aspect
public class MyAspect{
    @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))", returning = "res")
    //JoinPoint必须在第一位。
    public void myAfterReturning(JoinPoint jp, Object res){
       //Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理。
        System.out.println("后置通知,方法的定义:" + jp.getSignature());
        System.out.println("后置通知,在目标方法之后执行,获取的返回值是:" + res);
        if("xxx".equals(res)){
            //做一些功能
        }else{
            //做其他功能。
        }
        
        //修改目标方法的返回值
        if(res != null){
            res = "yyy";//不会变
            //如果是引用类型,可以改变引用类型的内容。
        }
    }
}
3.5.7 @Around 环绕通知

@Around环绕通知

环绕通知方法定义格式:

public必须有一个返回值,推荐使用Object方法名称自定义方法有参数,并且是固定的——ProceedingJoinPoint 属性:

value:切入点表达式 位置:在方法定义的上方。特点:

它是功能最强的通知。在目标方法的前和后都能增强功能。能控制目标方法是否被调用执行修改原来的目标方法的执行结果,影响最后的调用结果。 环绕通知,等同于JDK的动态代理,InvocationHandler接口参数:

ProceedingJoinPoint 就等同于JDK动态代理中的method作用:执行目标方法ProceedingJoinPoint接口继承了JoinPoint接口,可以获得参数,从而控制方法的执行。 返回值:就是目标方法的执行结果,可以被修改。环绕通知经常做事务,在目标方法开启事务,执行目标方法,在目标方法之后提交事务。

@Aspect
public class MyAspect{
    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
        //获取第一个参数
        Object[] args = pjp.getArgs();
        String name = "";
        if(args != null && args.length > 1){
            name = (String)args[0];
        }
        //实现环绕通知的功能
        Object res = null;
        //目标方法执行之前加入功能
        System.out.println("环绕通知:目标方法执行之前加入功能");
        
        //1. 目标方法调用
        //该方法会有异常,要上抛
        if("zhangsan".equals(name)){
            res = pjp.proceed();//相当于method.invoke();	相当于Object res = doFirst();
        }
        //目标方法执行之后加入功能
        System.out.println("环绕通知:目标方法执行之后加入功能");
        //2. 在目标方法的前或后加入功能
        
        //修改目标方法的执行结果,影响方法最后的调用结果
        if(res != null){
            res = "xxx";
        }
        //3. 返回目标方法的执行结果
        return res;
    }
       
}
3.5 9 @AfterThrowing异常通知(了解)

AfterThrowing 异常通知

异常通知方法的定义要求:

公共方法public

方法没有返回值(void)

方法名称自定义

方法可以有参数,也可以没有参数。可以添加一个Exception类型的参数

@AfterThrowing(value = "...", throwing = "ex")
public void myAfterThrowing(Exception ex){
    //输出异常信息
    System.out.println(ex.getMessage());
}

如果有参数,参数不是自定义的,有几个参数类型可以使用。

在目标方法抛出异常后执行。

该注解的 throwing 属性用于指定所发生的异常类对象。 当然,被注解为异常通知的方法可以包含一个参数 Throwable,参数名称为 throwing 指定的名称,表示发生的异常对象。

在效果上相当于一个try…catch语句。目标方法的方法体在try语句块中,而切面方法的方法体放在了catch子句中。

3.5.9 @After最终通知

@After最终通知

最终通知方法的定义要求:

公共方法public方法没有返回值(void)方法名称自定义方法可以有参数,也可以没有参数。如果有,就是JoinPoint。 属性:value 切入点表达式特点:

总是会执行,即使发生异常了也会执行。相当于try…catch中的finally。在目标方法之后执行。一般做资源清理工作。 3.5.10 @Pointcut

@Pointcut

不是通知注解,只是一个辅助注解。

定义和管理切入点。

属性:value 切入点表达式

位置:在自定义方法的上面。

特点:

当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名。其他的通知中,value属性就可以使用这个方法名称,代替切入点表达式。

如果在一个Aspect类中有很多通知,并且很多通知都有一个重复的切入点表达式,就可以对切入点表达式进行定义。

@After(value = "mypt()")
   public void myAfter(){
       System.out.println("最终通知,总是会被执行的,可以做程序最后要做的工作,例如资源回收,内存释放");
   }
 
   
   @Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))")
   private void mypt(){
       //无需代码
   }
3.5.11 指定cglib动态代理




第四章 Spring集成MyBatis 4.1 概述

Spring集成myBatis,其本质工作就是:将使用mybatis框架时用到的一些需要自己创建的对象,交由Spring统一管理。

使用的技术:ioc

主要有以下对象:

数据源dataSource。就是保存数据库连接信息的对象。

在实际业务开发中,我们放弃使用Mybatis自带的数据库连接池,而采用阿里的Druid,更加高效;

生成sqlSession对象的sqlSessionFactory;

Dao接口的实现类对象。

MyBatis使用步骤:

第一步:定义dao接口 ,StudentDao

第二步:定义mapper文件 StudentDao.xml

第三步:定义mybatis的主配置文件 mybatis.xml

第四步:创建dao的代理对象

StudentDao dao = SqlSession.getMapper(StudentDao.class);
List students  = dao.selectStudents();

想要使用dao对象,需要使用getMapper()方法,怎么能使用getMapper()方法呢?需要哪些条件?

获取SqlSession对象, 需要使用SqlSessionFactory的openSession()方法。创建SqlSessionFactory对象。 通过读取mybatis的主配置文件,能创建SqlSessionFactory对象。

SqlSessionFactory-------->SqlSession-------->dao
Factory的创建需要读取主配置文件

4.2 Spring集成MyBatis创建项目的流程

第一步:新建Maven项目第二步:加入Maven依赖

spring依赖mybatis依赖mysql依赖spring的事务依赖mybatis和spring集成的依赖。 mybatis官方提供,用来在spring项目中创建mybatis的SqlSessionFactory,dao对象的。 第三步:创建实体类第四步:创建dao接口和mapper文件第五步:创建mybatis主配置文件第六步:创建Service接口和实现类,属性是dao第七步:创建spring的配置文件,声明mybatis的对象交给spring创建

数据源:dataSourceSqlSessionFactoryDao对象声明自定义的service 第八步:创建测试类,获取Service对象,通过service调用dao完成对数据库的访问。 4.2.1 添加maven依赖


    
      
      junit
      junit
      4.11
      test
    
    
    
      org.springframework
      spring-context
      5.3.15
    
    
    
      org.springframework
      spring-tx
      5.3.15
    
    
      org.springframework
      spring-jdbc
      5.3.15
    
    
    
      org.mybatis
      mybatis
      3.5.9
    
    
    
      org.mybatis
      mybatis-spring
      2.0.7
    
    
    
      mysql
      mysql-connector-java
      8.0.28
    
    
    
      com.alibaba
      druid
      1.2.8
    
  

将src/main/java目录下的xml,properties文件也会被扫描到classes文件夹中


    
      
        src/main/java
        
          ***.xml
        
        false
      
    
    
  
曾经的mybatis-config模板






    
    

    
        
            
            

                
                
                
                

            
        
    

    
    
        
    


mybatis-mapper模板





4.2.2 新建实体类Student
package com.bjpowernode.bean;

public class Student {
    private Integer id;
    private Integer age;
    private String name;
    private String email;


    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", email='" + email + ''' +
                ", age=" + age +
                '}';
    }

    public Student() {
    }

    public Student(Integer id, Integer age, String name, String email) {
        this.id = id;
        this.age = age;
        this.name = name;
        this.email = email;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

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

4.2.3 新建Dao接口和sql映射文件(Mapper)

Dao接口

package com.bjpowernode.dao;

import com.bjpowernode.bean.Student;

import java.util.List;

public interface StudentDao {
    int insertStudent(Student student);
    List selectStudents();
}

Sql映射文集:(Mapper)




    
        insert into t_student values(#{id}, #{age}, #{name}, #{email});
    
    
        select id, name, amount, price from t_goods where id = #{id};
    

SaleDao接口:

package com.bjpowernode.dao;

import com.bjpowernode.bean.Sale;

public interface SaleDao {
    
    int insertSale(Sale sale);
}

SaleDao.xml






    
        insert into t_sale(gid, nums) values(#{gid}, #{nums});
    

5.3.5 创建mybatis主配置文件





    
    
        
        
    

    
    
        
        
    

5.3.6 创建Service接口和实现类
package com.bjpowernode.service;

import com.bjpowernode.bean.Goods;
import com.bjpowernode.bean.Sale;

public interface SaleService {
    
    void buy(Sale sale);

    
    Goods selectGoods(Integer id);

}
package com.bjpowernode.service.impl;

import ...;

public class SaleServiceImpl implements SaleService {
    SaleDao saleDao = null;
    GoodsDao goodsDao = null;

    public void setSaleDao(SaleDao saleDao) {
        this.saleDao = saleDao;
    }

    public void setGoodsDao(GoodsDao goodsDao) {
        this.goodsDao = goodsDao;
    }

    
//    @Transactional(
//            propagation = Propagation.REQUIRED,
//            isolation = Isolation.DEFAULT,
//            readonly = false,
//            rollbackFor = {
//                    NotEnoughException.class
//            }
//    )

    //使用的是事务控制的默认值,默认的传播行为是REQUIRED,默认的隔离级别是DEFAULT,默认抛出运行时异常,回滚事务。
    @Transactional
    @Override
    public void buy(Sale sale) {
        //为了表现回滚异常,添加操作放前面。
        //添加销售记录
        saleDao.insertSale(sale);
        Goods goods = goodsDao.selectGoods(sale.getGid());
        if(goods.getAmount() - sale.getNums() < 0){
            throw new NotEnoughException("商品库存不足");
        }
        //当出现异常后,下列代码无法执行,会导致出现销售记录错误。
        //更新库存
        goodsDao.updateGoods(sale);
        System.out.println("销售成功");
    }

    @Override
    public Goods selectGoods(Integer id) {
        return goodsDao.selectGoods(id);
    }
}

5.3.7 创建spring主配置文件



    
    

    
    
        
        
        
        
    

    
    
        
        
    

    
    
        
        
    

    
    
        
        
    

    
    
    
        
        
    

    
    
    

5.3.8 创建测试类
package com.bjpowernode.test;

import com.bjpowernode.bean.Sale;
import com.bjpowernode.service.SaleService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test01 {
    @Test
    public void testService(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        SaleService service = (SaleService) ac.getBean("service");
        Sale sale = new Sale();
        sale.setGid(1001);
        sale.setNums(100);
        service.buy(sale);
    }
}

5.3.9 自定义异常
package com.bjpowernode.exception;

public class NotEnoughException extends RuntimeException{
    public NotEnoughException(String s){
        System.out.println(s);
    }
}
第六章 使用AspectJ的AOP配置管理事务

适合大型项目,有很多类、方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中声明类、方法需要的事务。这种方式业务方法和事务配置完全分离。

实现步骤:都是在xml配置文件中完成的。

第一步:要使用的是aspectj框架,需要加入依赖


    org.springframework
    spring-aspects
    5.3.15

第二步:声明事务管理器对象


第三步:声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)

第四步:配置aop:指定哪些哪类要创建代理。

6.1 添加依赖(pom.xml)

    org.springframework
    spring-aspects
    5.3.15

6.2 applicationContext.xml


	





	
    
    	
        
        					
        
        
        
        
        
         
    




    
    
    
    

第七章 web项目中使用容器对象

    普通测试项目做的是javase项目有main方法的,执行代码是执行main方法的,在main里面创建的容器对象

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    

    web项目是在tomcat服务器上运行的。 tomcat一起动,项目一直运行的。

    需求:
    web项目中容器对象只需要创建一次, 把容器对象放入到全局作用域ServletContext中。

    怎么实现?
    使用监听器:当全局作用域对象被创建时,创建容器,存入ServletContext。

    监听器的作用:
    1)创建容器对象,执行 ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);
    2)把容器对象放入到ServletContext, ServletContext.setAttribute(key,ctx)

    监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener

    实现:

    为了使用监听器对象,需要在pom.xml中添加依赖:

    
    	org.springframework
        spring-web
        5.3.15
    
    

    在web.xml文件中配置监听器

    
    	
        contextConfigLocation
        
        classpath:applicationContext.xml
    
    
    	...ContextLoaderListener
    
    

    在servlet中:

    public class RegisterServlet extends HttpServlet{
        protected void doPost(HttpServletRequest request, HttpServletResponse response){
            String ... = request.getParameter("...");
            ...
            //创建spring的容器对象,不使用ApplicationContext类,使用WebApplicationContext类
            WebApplicationContext wac = null;
            //获取ServletContext中的容器对象,创建好的容器对象,拿来就用。
            //String key = WebApplicationContext....
            
            //使用框架中的方法,获取容器对象
            ServletContext context = getServletContext();
            wac = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
            
            //合并
            WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext);
        }
    }
    

    WebApplication和Application的关系:

    private WebApplicationContext context;
    public interface WebApplicationContext extends ApplicationContext;
    
    ApplicationContext:javase项目中使用的容器对象
    WebApplicationContext:web项目中的使用的容器对象
    
    把创建的容器对象,放入到全局作用域
     key: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
           WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
     value:this.context
    
     servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
    
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/773576.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号