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

Spring

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

Spring

文章目录

Spring1、简介

1.1、什么是Spring1.2、Spring的优点1.3、Spring的体系结构1.4、扩展 2、什么是容器3、IOC容器

3.1、配置元数据3.2、如何去使用容器 4、Spring配置

4.1、Bean标签基本配置4.2、Bean实例化三种方式

1、构造函数实例化2、工厂静态方法实例化3、工厂实例方法实例化 4.3、Bean依赖注入

1、构造器注入2、Setter 注入

1、基本类型注入2、Bean对象注入3、数组注入4、list集合注入5、map集合注入6、set集合注入7、Null注入8、Properties注入 3、其他注入

1、P命名空间注入2、c 命名空间注入 4.4、Bean自动装配

1、byName2、byType 4.5、Bean作用域

singletonPrototypeRequestSessionApplication 4.6、Bean别名4.7、引入其他配置文件4.8、context标签4.9、懒加载机制 5、基于原始注解

简介配置@Component@Autowired@Qualifier@Resource@Value@Scope 6、Spring新注解

简介注解使用@Configuration@ComponentScan@import@Bean@PropertySource@MapperScan 7、代理模式

静态代理动态代理 8、AOP

1、什么是AOP?

1.2、AOP的作用以及优点1.3、AOP的动态代理技术 2、AOP 的相关术语3、导入jar包4、xml配置文件详解5、切点表达式6、通过 Spring API 实现7、自定义类实现8、使用注解实现 9、MyBatis-Spring

1、简介

什么是MyBatis-Spring?知识基础 2、导入依赖3、在spring中配置数据源4、在spring配置工厂5、创建SqlSession6、增加Mapper接口的实现类

方法一 10、Spring事务

1、什么是事务2、Spring中的事务管理

编程式事务管理声明式事务管理 3、通过xml方式实现事务

1、引入约束2、配置事务管理器3、配置事务通知4、织入事务 2、Spring中的事务管理

编程式事务管理声明式事务管理 3、通过xml方式实现事务

1、引入约束2、配置事务管理器3、配置事务通知4、织入事务

Spring 1、简介 1.1、什么是Spring

Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。

提供了展现层 SpringMVC 和持久层 Spring JDBCTemplate 以及业务层事务管理等众多的企业级应用技术 ,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。

2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。

2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。

Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术

官网 : http://spring.io/

官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/

GitHub : https://github.com/spring-projects

1.2、Spring的优点

方便解耦,简化开发声明式事务的支持Spring是一个轻量级的框架,非侵入式。(注:现在可能不是轻量的)控制反转IoC,面向切面Aop对事物的支持,集成各种优秀框架

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

1.3、Spring的体系结构

Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 。

Spring Core:核心容器,提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转IOC模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。Spring Context:继承BeanFactory,提供上下文信息,扩展出JNDI、EJB、电子邮件、国际化、校验和调度等功能。Spring AOP:Spring AOP 模块直接将面向切面的编程功能,集成到了Spring框架中,所以可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所以这些都遵从 Spring 的通用事务和 DAO 异常层次结构。Spring DAO:提供了JDBC的抽象层,还提供了声明性事务管理方法。并且极大地降低了需要编写地异常代码数据 (例如打开和关闭连接)。Spring Web:提供了基础的 Web 开发的上下文信息,现有的Web框架,如JSF、Tapestry、Structs等,提供了集成。Spring MVC:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架便成为高度可配置的,MVC 其中容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。 1.4、扩展

Spring Boot与Spring Cloud

Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;Spring Cloud是基于Spring Boot实现的;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。 2、什么是容器

从概念上来讲容器是Spring的核心,是用来管理对象的,容器将创建对象,把他们连接在一起,配置,并管理他们的整个生命周期从创建到销毁。org.springframework.context.ApplicationContext接口代表 Spring IoC 容器,负责实例化、配置和组装 bean。容器通过读取配置元数据获取有关要实例化、配置和组装哪些对象的指令。配置元数据以 XML、Java 注释或 Java 代码表示。它可以让您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。ApplicationContextSpring 提供了该接口的几种实现。在独立应用程序中,通常创建ClassPathXmlApplicationContext 或FileSystemXmlApplicationContext对象。 3、IOC容器

**控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,**也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,控制反转就是:获得依赖对象的方式反转了。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

3.1、配置元数据

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

导入jar包:


    org.springframework
    spring-webmvc
    5.3.13

applicationContext.xml配置文件:

一般spring容器叫(ApplicationContext.xml)配置文件。



	
      
        
        
    
    
    
        
    
    

3.2、如何去使用容器

ApplicationContext的实现类

实现类作用
ClassPathXmlApplicationContext它是从类的根路径下加载配置文件,推荐使用这种
FileSystemXmlApplicationContext它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
AnnotationConfigApplicationContext当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解

实例化容器,可以加载多个配置文件,去使用类的无参构造器创造类的对象,将对象注册在容器中。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml", "daos.xml");

getBean():获取容器中的bean

//getBean(String name, Class requiredType)获取实例对象
PetStoreService service = context.getBean("petStore", PetStoreService.class);
4、Spring配置 4.1、Bean标签基本配置

Spring 配置中可以有一个或者多个标签,处于中。bean定义对应于构成应用程序的实际对象。通常,定义服务层对象、数据访问对象(DAO)、表示对象(如Struts操作实例)、基础结构对象(如Hibernate SessionFactorys)、JMS队列等。通常,不在容器中配置细粒度域对象,因为创建和加载域对象通常是DAO和业务逻辑的责任。但是,可以使用Spring与AspectJ的集成来配置在IoC容器控制之外创建的对象。id:用于标识单个 bean ,变量名。

如果没有配置id,name就是默认标识符,如果配置id,又配置了name,那么name是别名。如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象。 class:属性定义 bean 的类型并使用完全限定的类名,对象。


    

4.2、Bean实例化三种方式 1、构造函数实例化

无参构造




2、工厂静态方法实例化 3、工厂实例方法实例化 4.3、Bean依赖注入

概念

依赖注入(Dependency Injection,DI)依赖:指Bean对象的创建依赖于容器,Bean对象的依赖资源。注入:指Bean对象所依赖的资源,由容器来设置和装配。 1、构造器注入

有参构造器注入


    
    




    
    




    

2、Setter 注入

要求被注入的属性,必须要有set方法,set方法的方法名由set + 属性首字母大写,如果属性是Boolean类型,没有set方法,是is方法。

测试类:

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Student {

    private String name;//基本类型
    private Address address;//实体属性
    private String[] books;//数组
    private List hobbys;//list集合
    private Map card;//map集合
    private Set games;//set集合
    private String wife;//Null,可能没有妻子
    private Properties info;//配置文件注入

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

    public void setAddress(Address address) {
        this.address = address;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public void setHobbys(List hobbys) {
        this.hobbys = hobbys;
    }

    public void setCard(Map card) {
        this.card = card;
    }

    public void setGames(Set games) {
        this.games = games;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    public void show(){
        System.out.println("name="+ name
                           + ",address="+ address.getAddress()
                           + ",books="
                          );
        for (String book:books){
            System.out.print("<<"+book+">>t");
        }
        System.out.println("n爱好:"+hobbys);

        System.out.println("card:"+card);

        System.out.println("games:"+games);

        System.out.println("wife:"+wife);

        System.out.println("info:"+info);

    }
}
1、基本类型注入

2、Bean对象注入

    


    

3、数组注入

    
        西游记
        红楼梦
        水浒传
    

4、list集合注入

    
        听歌
        看电影
        爬山
    

5、map集合注入

    
        
        
    

6、set集合注入

    
        LOL
        BOB
        COC
    

7、Null注入

    



    //这里是设为空字符串

8、Properties注入

    
        20190604
        
        小明
    

3、其他注入

p命名和c命名注入

1、P命名空间注入

首先,需要引入P命名空间:

xmlns:p="http://www.springframework.org/schema/p"

P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:

 
2、c 命名空间注入

构造器注入,需要有参构造

需要在头文件中加入约束文件

xmlns:c="http://www.springframework.org/schema/c"
 
 
4.4、Bean自动装配

Spring中bean有三种装配机制:

    在xml中显式配置;(使用ref显示装配)在java中显式配置;隐式的bean发现机制和自动装配。

概念

自动装配是使用spring满足bean依赖的一种方法spring会在应用上下文中为某个bean寻找其依赖的bean。

Spring的自动装配是如何实现的:

    组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
1、byName

autowire byName (按名称自动装配)

Spring 查找与需要自动装配的属性同名的 bean(根据id是否和属性名相同)。例如,如果一个 bean 定义被设置为按名称自动装配并且它包含一个master属性(即它有一个 setMaster(..)方法),Spring 会查找一个名为的 bean 定义master并使用它来设置属性。



   

2、byType

autowire byType (按类型自动装配)

如果容器中恰好存在一个属性类型的 bean,则让属性自动装配。如果存在多个,则会引发致命异常,不能byType为该 bean使用自动装配。如果没有匹配的 bean,则不会发生任何事情(未设置属性)。





   

自动装配的优缺点

优点:

自动装配可以显着减少指定属性或构造函数参数的需要。自动装配可以随着对象的发展更新配置。例如,如果需要向类添加依赖项,则无需修改配置即可自动满足该依赖项。因此,自动装配在开发过程中特别有用,当代码库变得更稳定时,不会否定切换到显式装配的选项。 4.5、Bean作用域

scope:指对象的作用范围,取值如下:

singleton

单例作用域(单例模式)

当定义一个 bean 定义并且它的作用域为单例时,Spring IoC 容器会创建该 bean 定义定义的对象的一个实例。该单个实例存储在此类单例 bean 的缓存中,并且对该命名 bean 的所有后续请求和引用都返回缓存对象。白话来说就是公用一个缓存里的对象Bean的实例化个数:1个Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例Bean的生命周期:

对象创建:当应用加载,创建容器时,对象就被创建了对象运行:只要容器在,对象一直活着对象销毁:当应用卸载,销毁容器时,对象就被销毁了

单例作用域是 Spring 中的默认作用域。要将 bean 定义为 XML 中的单例,如下例所示:





Prototype

原型作用域(原型模式)

bean 部署的非单一原型范围导致每次对特定 bean 发出请求时都会创建一个新 bean 实例。通常,对所有有状态 bean 使用原型作用域,对无状态 bean 使用单例作用域。Bean的实例化个数:多个Bean的实例化时机:当调用getBean()方法时实例化Bean

对象创建:当使用对象时,创建新的对象实例对象运行:只要对象在使用中,就一直活着对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了

以下示例将 bean 定义为 XML 中的原型:


Request

考虑 bean 定义的以下 XML 配置:


Spring 容器LoginAction通过loginAction对每个 HTTP 请求使用bean 定义来创建bean 的新实例。也就是说, loginActionbean 的范围在 HTTP 请求级别。您可以根据需要更改所创建实例的内部状态,因为从同一loginActionbean 定义创建的其他实例不会看到这些状态更改。它们是针对个人要求的。当请求完成处理时,该请求范围内的 bean 将被丢弃。

当使用注解驱动的组件或 Java 配置时,@RequestScope注解可用于将组件分配给request作用域。以下示例显示了如何执行此操作:

@RequestScope
@Component
public class LoginAction {
    // ...
}
Session

考虑 bean 定义的以下 XML 配置:


Spring 容器UserPreferences通过在userPreferences单个 HTTP 的生命周期中使用bean 定义来创建bean 的新实例Session。换句话说,userPreferencesbean 有效地限定在 HTTPSession级别。与请求范围的 bean 一样,您可以根据需要更改所创建实例的内部状态,因为知道Session也使用从相同userPreferencesbean 定义创建的实例的其他 HTTP实例不会看到这些状态更改,因为它们特定于单个 HTTP Session。当 HTTPSession最终被丢弃时,作用域为该特定 HTTP 的 bean Session也将被丢弃。

当使用注解驱动的组件或 Java 配置时,可以使用 @SessionScope注解将组件分配给session作用域。

@SessionScope
@Component
public class UserPreferences {
    // ...
}
Application

考虑 bean 定义的以下 XML 配置:


Spring 容器AppPreferences通过appPreferences对整个 Web 应用程序使用一次 bean 定义来创建bean 的新实例。也就是说, appPreferencesbean 的作用域在ServletContext级别并存储为常规 ServletContext属性。这有点类似于 Spring 单例 bean,但在两个重要方面有所不同:它是一个单例 per ServletContext,而不是 per Spring ApplicationContext(在任何给定的 Web 应用程序中可能有多个),并且它实际上是公开的,因此作为一个ServletContext属性可见.

当使用注解驱动的组件或 Java 配置时,可以使用 @ApplicationScope注解将组件分配给application作用域。以下示例显示了如何执行此操作:

@ApplicationScope
@Component
public class AppPreferences {
    // ...
}
4.6、Bean别名

在 Bean 定义之外给 Bean 取别名


4.7、引入其他配置文件

团队的合作通过import来实现 ,导入其他的容器xml文件


4.8、context标签

使用context标签之前需要引入context约束

开启注解支持:


指定注解扫描包:支持自动将包下的类自动创建bean并注册到spring容器中,包含开启注解支持功能)


用于加载.properties 文件中的配置:


4.9、懒加载机制

xml中:

设置某个对象使用懒加载机制


    

开启全局懒加载:在XML的beans标签中配置:

default-lazy-init="true":设置全局受管对象懒加载,当第一次使用该对象时才创建

注解中:

设置某个对象使用懒加载机制使用@Lazy注解

@Bean
@Lazy
public UserDao userDao(){
    UserDaoImpl userDao = new UserDaoImpl();
    return userDao;
}

开启全局懒加载,将该注解加到配置文件头中

@Configuration
@ComponentScan("com.pip")
@Lazy
public class Config {
}
5、基于原始注解 简介

概念

Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置 文件可以简化配置,提高开发效率。

快速说明

注解说明
@Component使用在类上用于实例化Bean
@Controller使用在web层类上用于实例化Bean
@Service使用在service层类上用于实例化Bean
@Repository使用在dao层类上用于实例化Bean
@Autowired使用在字段上用于根据类型依赖注入
@Qualifier结合@Autowired一起使用用于根据名称进行依赖注入
@Resource相当于@Autowired+@Qualifier,按照名称进行注入
@Value注入普通属性
@Scope标注Bean的作用范围
@PostConstruct使用在方法上标注该方法是Bean的初始化方法
@PreDestroy使用在方法上标注该方法是Bean的销毁方法

注解使用

配置

引入依赖jar包:spring-aop jar包

引入context约束




配置扫描哪些包下的注解:

使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean 需要进行扫描以便识别使用注解配置的类、字段和方法。


@Component

使用@Compont或@Repository标识相应的类需要Spring进行实例化。在指定包下编写类,增加注解默认对象名为类名首字母小写(user)可通过value赋对象名

@Component("user")//id可加可不加
// 相当于配置文件中 
public class User {
   public String name = "pip";
}

@Component三个衍生注解

和Component功能一模一样,只是名字不同

@Controller:web层@Service:service层@Repository:dao层 @Autowired

概念

@Autowired是根据类型自动装配的,不支持id匹配。@Autowired可以加到属性或者方法上可以不用写set方法,但是不建议!使用@Compont或@Service标识UserServiceImpl需要Spring进行实例化使用@Autowired或者@Autowired+@Qulifier或者@Resource进行userDao的注入

配置**applicationContext.xml文件:**



    
    
    
    
    
    

    
        
    

Bean

//说明:false,对象可以为null;true,对象必须存对象,不能为null。
@Autowired(required=false)
private Cat cat;
@Autowired
private Dog dog;
private String u_name;
@Qualifier

@Qualifier不能单独使用。@Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配

@Autowired(required=false)
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
private Dog dog;
private String u_name;
@Resource

@Resource如有指定的name属性,先按该属性进行byName方式查找装配;其次再进行默认的byName方式进行装配;如果以上都不成功,则按byType的方式自动装配。

@Autowired与@Resource异同:

1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用。

3、@Resource(属于J2EE复返),相当于@Autowired+@Qualifier,按照名称进行注入,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

@Value

使用注解注入基本属性,可加在set方法中。

一般用于加载外部文件,基本属性不用这个方法注入。

@Component("user")
// 相当于配置文件中 
public class User {
    @Value("pip")
    // 相当于配置文件中 
    public String name;
}
@Scope

使用@Scope标注Bean的范围

singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。

prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收

@Controller("user")
@Scope("prototype")
public class User {
   @Value("pip")
   public String name;
}
6、Spring新注解 简介

概念

使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下

快速说明

注解说明
@Configuration用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定 Spring 在初始化容器时要扫描的包。 作用和在 Spring 的 xml 配置文件中的一样
@Bean使用在方法上,标注将该方法的返回值存储到 Spring 容器中
@PropertySource用于加载.properties 文件中的配置
@import用于导入其他配置类
注解使用
@Configuration

用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解

@Configuration
public class SpringConfiguration {
}
@ComponentScan

用于指定 Spring 在初始化容器时要扫描的包。 作用和在 Spring 的 xml 配置文件中的一样

@ComponentScan("com.pip")//等同于
@ComponentScan({"com.pip.dao","com.pip.service"})
public class SpringConfiguration {
}
@import

用于导入其他配置类

@Configuration
@ComponentScan("com.pip")
@import(DataSourceConfiguration.clas)
@import({DataSourceConfiguration.class,DataSourceConfiguration2.class})//与功能一样
public class SpringConfiguration {
}
@Bean

相当于之前的标签使用在方法上,标注将该方法的返回值存储到 Spring 容器中

@Bean和@Component可以分开使用也可以同时使用,我觉得并无差别

@Configuration
public class AppConfig {

    @Bean("name")//name可加可不加不加的方法名就是n
    public Bean bean() {
        return new Bean();
    }
}
@PropertySource

用于加载.properties 文件中的配置

@PropertySource("classpath:jdbc.properties")
@MapperScan

Mapper自动生成实现类

@MapperScan("com.pip.goods.mapper")
7、代理模式

这里简单阐述一下JDK的代理技术

静态代理

静态代理分析

抽象对象 : 一般使用接口或者抽象类来实现真实对象 : 被代理的角色代理对象 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作。如增加日志等调用对象 : 使用代理角色来进行一些操作。

都学到这里了,我就不通过实际例子来说明了,通过代码进行举例

抽象对象:

public interface AbstractSubject {
    void method();
}

真实对象:

public class RealSubject implements AbstractSubject{
    @Override
    public void method() {
        System.out.println("真实对象中的method方法");
    }
}

代理对象:

public class Proxy implements AbstractSubject{
    private RealSubject rs;

    public void setRs(RealSubject rs) {
        this.rs = rs;
    }

    @Override
    public void method() {
        log();
        rs.method();
    }
    
    
    public static void log(){
        System.out.println(new Date);
    }
}

调用对象:

RealSubject rs = new RealSubject();
Proxy proxy = new Proxy();
//注入真实对象到代理对象中
proxy.setRs(rs);
//调用代理对象的方法
proxy.method();
//结果:
//Thu Nov 25 01:18:24 CST 2021
//真实对象中的method方法

缺点:每一个代理对象都需要我们去编写,非常的耗时耗力,通过动态代理解决。

动态代理

基于类的动态代理–cglib,我没学就不记了

动态代理的对象和静态代理相同

抽象对象:

public interface AbstractSubject {
    void method();
}

真实对象:

public class RealSubject implements AbstractSubject{
    @Override
    public void method() {
        System.out.println("真实对象中的method方法");
    }
}

动态生成代理对象:

核心 : InvocationHandler 和 Proxy

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

public class ProxyInvocationHandler implements InvocationHandler {
    private Object object;

    public void setObject(Object object) {
        this.object = object;
    }
		
    //生成动态代理对象
    //Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h);	
    //loader:定义代理类的类加载器
	//interfaces:代理类要实现的接口列表     
	//h:指派方法调用的调用处理程序
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                object.getClass().getInterfaces(),this);
    }

     
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置增强");
        Object o = method.invoke(object, args);
        System.out.println("后置增强");
        return o;
    }
}

调用对象:

RealSubject rs = new RealSubject();
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//添加真实对象到代理对象中
pih.setObject(rs);
//动态代理接口中的方法
AbstractSubject proxy = (AbstractSubject) pih.getProxy();
//代理对象调用方法
proxy.method();
8、AOP 1、什么是AOP?

AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP底层是通过动态代理实现的!在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。

1.2、AOP的作用以及优点

作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强。优点:减少重复代码,提高开发效率,并且便于维护。 1.3、AOP的动态代理技术

常用的动态代理技术

JDK 代理 : 基于接口的动态代理技术cglib 代理:基于父类的动态代理技术 2、AOP 的相关术语

Target(目标对象):代理的目标对象Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类。Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。(被增强的方法)Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。(即,它是切面类中的一个方法)Aspect(切面):是切入点和通知(引介)的结合。(即,它是一个类)Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而 AspectJ采用编译期织入和类装载期织入。(将切点与通知结合的过程) 3、导入jar包


    org.aspectj
    aspectjweaver
    1.9.7



    org.springframework
    spring-webmvc
    5.3.13

4、xml配置文件详解

导入aop约束

aop织入的配置


	
        
	

如果多个切点表达式相同可以抽取切点表达式,通知通过pointcut-ref引入。

 

通知的类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知

     
名称标签说明
前置通知用于配置前置通知。指定增强的方法在切入点方法之前执行
后置通知用于配置后置通知。指定增强的方法在切入点方法之后执行
环绕通知用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行
异常抛出通知用于配置异常抛出通知。指定增强的方法在出现异常时执行
最终通知用于配置最终通知。无论增强方式执行是否有异常都会执行
5、切点表达式
execution([修饰符] 返回值类型 包名.类名.方法名(参数))

访问修饰符可以省略返回值类型、包名、类名、方法名可以使用星号* 代表任意包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表

例如:

execution(public void com.pip.aop.Target.method())
execution(void com.pip.aop.Target.*(..))
execution(* com.pip.aop.*.*(..))
execution(* com.pip.aop..*.*(..))
execution(* *..*.*(..))
6、通过 Spring API 实现

通过API接口实现

编写接口类:

public interface UserService {
    void add();
    void delete();
    void uadate();
    void select();
}

实现类:

import org.springframework.stereotype.Component;

@Component()
public class UserServiceImpl implements UserService{

    @Override
    public void add() {
        System.out.println("添加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void uadate() {
        System.out.println("修改了一个用户");
    }

    @Override
    public void select() {
        System.out.println("查询用户");
    }
}

编写增强类,这里编写两个,一个前置增强 一个后置增强:

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeLog implements MethodBeforeAdvice {
    //method : 要执行的目标对象的方法
    //objects : 被调用的方法的参数
    //Object : 目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + "的" + method.getName()+ "方法被执行了");
    }
}

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
    //returnValue 返回值
    //method被调用的方法
    //args 被调用的方法的对象的参数
    //target 被调用的目标对象
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了" + target.getClass().getName()
                +"的"+method.getName()+"方法,"
                +"返回值:"+returnValue);
    }
}

编写xml配置文件:




    
    
    
    
    
    
    
        
        
        
        
        
    

测试:

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//通过接口中的方法去实现,动态代理原理
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.add();
userService.uadate();
userService.delete();
userService.select();
7、自定义类实现

通过切面实现

接口与实现类与第一种方式相同

自定义切入类:

public class DiyPointcut {
    public void before(){
        System.out.println("---------方法执行前---------");
    }
    public void after(){
        System.out.println("---------方法执行后---------");
    }
}

编写xml配置文件:




    
    
    
    
    
    
    
        
        
            
            
            
            
            
        
    

测试:

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.add();
userService.uadate();
userService.delete();
userService.select();
8、使用注解实现

接口类与实现类还是第一个编写一个@Aspect增强类:

@Component//交给spring进行管理
@Aspect//指定使用该注解的类为一个切面类
@EnableAspectJAutoProxy//启用AOP的自动代理(开启Spring AOP模式)

public class AnnotationPointcut {
    //抽取切入点
    @Pointcut("execution(* com.pip.Service.UserServiceImpl.*(..))")
    public void myPoint(){}
    
    @Before("AnnotationPointcut.myPoint()")
    public void before(){
        System.out.println("---------方法执行前---------");
    }

    @After("execution(* com.pip.Service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("---------方法执行后---------");
    }
	
    
    @AfterThrowing("myPintCut()")//异常通知注解
    public void afterAhrowing(){
        System.out.println("执行异常通知....");
    }

    
    @After("myPintCut()")//最终通知注解
    public void after(){
        System.out.println("执行最终通知....");
    }

    //环绕通知
    //环绕通知的参数必须为ProceedingJoinPoint
    //ProceedingJoinPoint参数中包含了目标方法及其他封装的操作
    @Around("execution(* com.pip.Service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        System.out.println("签名:"+jp.getSignature());
        //执行目标方法proceed
        Object proceed = jp.proceed();
        System.out.println("环绕后");
        System.out.println(proceed);
    }
}

测试:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationContext.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.add();
userService.uadate();
userService.delete();
userService.select();

注解配置 AOP 详解

    使用**@Aspect**标注切面类

    使用@通知注解标注通知方法

    通知的配置语法:@通知注解(“切点表达式")

    名称注解说明
    前置通知@Before用于配置前置通知。指定增强的方法在切入点方法之前执行
    后置通知@AfterReturning用于配置后置通知。指定增强的方法在切入点方法之后执行
    环绕通知@Around用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行
    异常抛出通知@AfterThrowing用于配置异常抛出通知。指定增强的方法在出现异常时执行
    最终通知@After用于配置最终通知。无论增强方式执行是否有异常都会执行

    抽取切点表达式

@Pointcut("execution(* com.pip.Service.UserServiceImpl.*(..))")
    public void myPoint(){}
@Before("切入类名.myPoint()")
    public void before(){}

    在配置文件中配置aop自动代理:@EnableAspectJAutoProxy

    proxy-target-class:默认为false,设为true表示使用CGLib动态代理技术织入增强,即使proxy-target-class设置为false,但是如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

9、MyBatis-Spring 1、简介 什么是MyBatis-Spring?

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。

不在需要mybaties-config配置文件,但可以在mybaties-config中保留一些MyBatis 的基础配置




    
    
        
    
    
    
    

知识基础

使用MyBatis-Spring之前需要导入各个jar包的版本

MyBatis-SpringMyBatisSpring 框架Spring BatchJava
2.03.5+5.0+4.0+Java 8+
1.33.4+3.2.2+2.1+Java 6+
2、导入依赖

    junit
    junit
    4.11
    test



    org.springframework
    spring-webmvc
    5.3.13



    org.springframework
    spring-jdbc
    5.3.13



    org.mybatis
    mybatis
    3.5.7



    mysql
    mysql-connector-java
    8.0.26



    org.mybatis
    mybatis-spring
    2.0.6



    org.aspectj
    aspectjweaver
    1.9.7

3、在spring中配置数据源

将数据源配置移交给Spring容器管理

jdbc.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456

加载配置文件

@PropertySource("classpath:jdbc.properties")

spring配置

@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;


@Bean
public DataSource dataSource(){
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName(driver);
    dataSource.setUrl(url);
    dataSource.setUsername(username);
    dataSource.setPassword(password);
    return dataSource;
}
4、在spring配置工厂

将SqlSessionFactory工厂交给spring来管理

SqlSessionFactory需要一个 DataSource(数据源)。这可以是任意的 DataSource,只需要和配置其它 Spring 数据库连接一样配置它就可以了。在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder 来创建 SqlSessionFactory 的。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建。configLocation:它用来指定 MyBatis 的 XML 配置文件路径。它在需要修改 MyBatis 的基础配置非常有用。通常,基础配置指的是 < settings> 或 < typeAliases>元素。mapperLocations:关联Mapper.xml配置文件,相当于mybaties配置中的

@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
    sqlSessionFactory.setDataSource(dataSource);
    return sqlSessionFactory.getObject();
}
5、创建SqlSession

SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession。 SqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器所共享使用。

(白话意思是在MyBatis中,可以使用 SqlSessionFactory 来创建 SqlSession,但它线程不安全,在MyBatis-Spring使用SqlSessionTemplate代替SqlSession)

当调用 SQL 方法时(包括由 getMapper() 方法返回的映射器中的方法),SqlSessionTemplate 将会保证使用的 SqlSession 与当前 Spring 的事务相关。 此外,它管理 session 的生命周期,包含必要的关闭、提交或回滚操作。另外,它也负责将 MyBatis 的异常翻译成 Spring 中的 DataAccessExceptions。


    
    

注意!!!如果你的接口实现类去继承了SqlSessionDaoSupport,请跳过这一步,直接到6的方法二!!!

6、增加Mapper接口的实现类
方法一

私有化sqlSessionTemplate

在spring中注册接口实现类的bean


    
    

//接口
public interface UserMapper {
    List query();
}

public class UserMapperImpl implements UserMapper{
    private SqlSessionTemplate sqlSession;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSession = sqlSessionTemplate;
    }
	
    @Override
    public List query() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.query();
    }
}

方法二

接口实现类去继承SqlSessionDaoSupport类

SqlSessionDaoSupport的原理就是方法一

SqlSessionDaoSupport具有getSqlSession() 方法 , 可以将SqlSessionFactory直接注入。比起方式一 , 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好,可跟踪源码查看。

在spring中注册接口实现类的bean


    
    

接口实现类

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List query() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.query();
    }
}
10、Spring事务 1、什么是事务

事务把一些列动作当成一个独立的工作单元,简单来说,这些动作要么全部完成,要么全部不起作用。

事务四大原则ACID(面试重点)

原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。隔离性:数据库允许多个并发事务同时对一个相同数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。持久性:事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中 2、Spring中的事务管理

Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。

编程式事务管理

将事务管理代码嵌到事务方法中来控制事务的提交和回滚。缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码 声明式事务管理

将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译 ,这样维护起来极其方便将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。 3、通过xml方式实现事务 1、引入约束

在配置文件中,引入约束:tx

xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
2、配置事务管理器

无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。Spring的核心事务管理抽象,管理封装了一组独立于技术的方法


    

3、配置事务通知

:配置事务通知,绑定事务管理器

name:切点方法名称。*代表所有方法isolation:事务的隔离级别propogation:事务的传播行为

名称作用
REQUIRED支持当前事务,如果当前没有事务,就新建一个事务。默认为这个选择
NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作

timeout:超时时间read-only:是否只读


    
        
    

4、织入事务

    
    
    


事务从来没有执行过一样。

一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。隔离性:数据库允许多个并发事务同时对一个相同数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。持久性:事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中 2、Spring中的事务管理

Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。

编程式事务管理

将事务管理代码嵌到事务方法中来控制事务的提交和回滚。缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码 声明式事务管理

将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译 ,这样维护起来极其方便将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。 3、通过xml方式实现事务 1、引入约束

在配置文件中,引入约束:tx

xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
2、配置事务管理器

无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。Spring的核心事务管理抽象,管理封装了一组独立于技术的方法


    

3、配置事务通知

:配置事务通知,绑定事务管理器

name:切点方法名称。*代表所有方法isolation:事务的隔离级别propogation:事务的传播行为

名称作用
REQUIRED支持当前事务,如果当前没有事务,就新建一个事务。默认为这个选择
NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作

timeout:超时时间read-only:是否只读


    
        
    

4、织入事务

    
    
    

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/750619.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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