Spring5 学习笔记!

1、Spring

    1.1、简介

 

  • Spring: 春天---->给软件行业带来了春天
  •  2002,首次推出了Spring框架的雏形:interface21框架!
  • Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版
  • Rod Johnson ,Spring Framework 创始人,著名作者。很难想象 Rod Johnson 的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
  • Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
 
  • SSH:Struct2+ Spring +Hibernate
  • SSM:SpringMvc + Spring +Mybatis

 

官网:https://spring.io/projects/spring-framework#overview

Spring Framework中文文档: https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/overview.html#overview-philosophy
 
 
 
 


    org.springframework
    spring-web
    5.2.0.RELEASE



    org.springframework
    spring-jdbc
    5.2.0.RELEASE

 

1.2、优点

  • Spring是一个开源的免费的框架(容器)!
  • Spring是一个轻量级的、非入侵式的框架!
  • 控制反转(IOC),面向切面编程(AOP)!
  • 支持事务的处理,对框架整合的支持!

 

总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!

 

 

1.3、组成

Spring5 学习笔记!_第1张图片

 

1.4、扩展

在Spring的官网有这个介绍:现代化的Java开发!说白了就是基于Spring的开发!

Spring5 学习笔记!_第2张图片

 

  • Spring Boot
    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速的开发单个微服务
    • 约定大于配置!
  • Spring Cloud
    • SpringCloud是基于Spring Boot实现的。
 
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMvc!承上启下的作用!
 
 
 
弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称: "配置地狱!"
 
 
 
 

2、IOC理论推导

1、UserDao接口

2、UserDaoImpl实现类

3、UserService业务接口

4、UserServiceImpl 业务实现类

 
 
 
 
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!
 
 
我们使用一个Set接口实现:
    private UserDao userDao;


    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

 

  • 之前,程序是主动创建对象!控制权在程序猿手上!
  • 使用set注入后,程序不再具有主动性,而是被动的接收对象!

这种思想,从本质上解决了问题,我们程序猿不再去管理对象的创建了。系统的耦合性大大降低~,可以更加专注在业务的实现上!这是IOC的原型!

 

 

IOC本质

控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一张说法。没有IOC的程序中,我们使用面向对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

 

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

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

 

3、HelloSpring

创建beans.xml:




   
    
        
    

创建Hello实体类:

package com.kuang.pojo;

/**
 * @Author panghl
 * @Date 2021/3/16 21:27
 * @Description TODO
 **/
public class Hello {

    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

 

测试:

import com.kuang.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author panghl
 * @Date 2021/3/16 21:31
 * @Description TODO
 **/
public class MyTest {
    public static void main(String[] args) {
        //获取Spring的上下文对象!
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在Spring中的管理,我们要使用,直接去里面取出来就可以了!
        Hello hello = (Hello)context.getBean("hello");
        System.out.println(hello.getStr());


    }
}

 

ok,到了现在,我们彻底不用在程序中去改动了,要实现不同的操作,只需在xml配置文件中进行修改,所谓的IOC,一句话搞定:对象由Spring来创建,管理,装配!

 

4、IOC创建对象的方式

1、使用无参构造创建对象,默认!

2、假设我们要使用有参构造创建对象

  1. 下标赋值

        
        
            
        

     

  2. 类型

        
        
            
        

     
  3. 参数名

        
        
            
        

     

总结:在配置文件加载的时候,容器中管理的所有对象已经被初始化了!

 

5、Spring配置

5.1、别名

    
    

 

5.2、Bean的配置

    
    
        
    

5.3、import

这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个!

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

  • 张三
  • 李四
  • 王五
  • applicationContext.xml



    
    

使用的时候,直接使用总的配置就可以了!


import com.panghl.pojo.User;
import com.panghl.pojo.UserT;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author panghl
 * @Date 2021/3/16 21:31
 * @Description TODO
 **/
public class MyTest {
    public static void main(String[] args) {
        //Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserT hello = (UserT) context.getBean("userT2");
        hello.show();
        System.out.println(hello.getName());
    }
}

 

6、依赖注入

6.1、构造器注入

4.2已经说过了!

6.2、Set方式注入【重点】

  • 依赖注入:Set注入!
    • 依赖:bean对象的创建依赖于容器!
    • 注入:bean对象中的所有属性,由容器来注入!

 

【环境搭建】

1、复杂类型

package com.panghl.pojo;

/**
 * @Author panghl
 * @Date 2021/3/16 22:30
 * @Description TODO
 **/
public class Address {
    private String adress;

    public String getAdress() {
        return adress;
    }

    public void setAdress(String adress) {
        this.adress = adress;
    }
}

2、真实测试对象

package com.panghl.pojo;

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

/**
 * @Author panghl
 * @Date 2021/3/16 22:30
 * @Description TODO
 **/
public class Student {

    private String name;
    private Address address;
    private String[] books;
    private List hobbys;
    private Map card;
    private Set games;
    private String wife;
    private Properties info;

    public String getName() {
        return name;
    }

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

    public Address getAddress() {
        return address;
    }

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

    public String[] getBooks() {
        return books;
    }

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

    public List getHobbys() {
        return hobbys;
    }

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

    public Map getCard() {
        return card;
    }

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

    public Set getGames() {
        return games;
    }

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

    public String getWife() {
        return wife;
    }

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

    public Properties getInfo() {
        return info;
    }

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

3、beans.xml




    
        
    

    
        
        
        
        

        
        
            
                红楼梦
                西游记
                水浒传
                三国演义
            
        

        
        
            
                听课
                看电影
                敲代码
            
        

        
        
            
                
                
            
        

        
        
            
                Lol
                cs
                BOB
            
        

        
        
            
        

        
        
            
                174061000
                pangh1000
                
            
        

    


4、测试类

import com.panghl.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author panghl
 * @Date 2021/3/16 21:31
 * @Description TODO
 **/
public class MyTest {
    public static void main(String[] args) {
        //Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student)context.getBean("student");
        System.out.println(student.toString());
    }
}

Spring5 学习笔记!_第3张图片

 

6.3、拓展方式注入

我们可以使用p命令和c命令进行注入

官方解释:

Spring5 学习笔记!_第4张图片

使用:



    


    

测试:

import com.panghl.pojo.Student;
import com.panghl.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author panghl
 * @Date 2021/3/16 21:31
 * @Description TODO
 **/
public class MyTest {
    public static void main(String[] args) {
        //Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml","userbeans.xml");
        Student student = (Student)context.getBean("student");
        System.out.println(student.toString());

        User user = (User)context.getBean("user");
        System.out.println(user.getName());

        User user2 = (User)context.getBean("user2");
        System.out.println(user2.getName());
    }
}

 

6.4、bean的作用域

Spring5 学习笔记!_第5张图片

Spring5 学习笔记!_第6张图片

1、单例模式(Spring 默认机制)
    

 

2、原型模式:每次从容器中get的时候,都会产生一个新对象!

3、其余的request、session、application、这些个只能在web开发中使用到!

 

7、Bean的自动装配

  • 自动装配Spring满足bean依赖一种方式!
  • Spring会在上下文中自动寻找,并自动给bean装配属性!

 

在Spring中有三种装配方式

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式的自动装配bean【重要】

 

7.1、测试

环境搭建:一个人有两个宠物!

 

 

7.2、ByName自动装配

    
    
        
    

7.3、ByType自动装配







    
    
        
    

 

小结:
  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
  • btType的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

 

7.4、注解实现自动装配

jdk1.5支持的注解!Spring2.5就支持注解!

基于注解的配置的引入提出了一个问题,即这种方法是否比 XML“更好”。简短的答案是“取决于情况”。

要使用注解须知:
1、导入约束:context约束
 
2、配置注解的支持 :     【重要】



    

 

@Autowired

 

直接在属性上使用注解即可!也可以在set方式上使用!
使用Autowired我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(Spring) 容器中存在,且符合名字byName!
 
 
科普:
 
@Nullable   字段标记了这个注解,说明这个字段可以为null
 
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * 

Defaults to {@code true}. */ boolean required() default true; }

 

 
测试代码:
    //如果显示定义了AutoWired的required属性为false,说明这个对象可以为null,否则不允许为空
    @Autowired(required = false)
    private Cat cat;
    @Autowired
    private Dog dog;
    private String name;

 

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们可以使用@Qualifier(value="xxx")去配置@Autowired的使用,指定一个唯一的bean对象注入!
 
 
 
    @Resource 注解
public class People {
    @Resource(name = "cata")
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog2222")
    private Dog dog;
    private String name;
}
 

小结:

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过byType的方式实现,如果有多个相同的类型根据byName实现,而且必须要求这个对象存在!
  • @Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到,就报错!【常用】
  • 执行顺序不同:@Autowired通过byType的方式实现。@Resource默认通过byName的方式实现。
 
 

8、使用注解开发

在Spring4之后,要使用注解开发,必须要保证aop的包导入了

Spring5 学习笔记!_第7张图片

1、bean

//等价于
//@Component 组件
@Component
public class User {
    public String name = "panghl";
}

2、属性如何注入

@Component
public class User {

    public String name;

    //相当于
    @Value("panghl2")
    public void setName(String name) {
        this.name = name;
    }
}

3、衍生的注解

@Component 有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!

  • dao【@Repository】
  • service【@Service】
  • controller 【@Controller】

这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean

 

4、自动装配

  • @Autowired通过byType的方式实现,如果有多个相同的类型根据byName实现,而且必须要求这个对象存在!
    • 如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们可以使用@Qualifier(value="xxx")去配置@Autowired的使用,指定一个唯一的bean对象注入!
  • @Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到,就报错!【常用】

5、作用域

@Scope("prototype")

6、小结

 
xml与注解:
  • xml更加万能,适用于任何场合!维护简单方便
  • 注解 不是自己类使用不了,维护相对复杂

xml与注解最佳实践:

  • xml用来管理bean;
  • 注解只负责完成属性的注入;
  • 我们在使用的过程中,只需要注解一个问题:必须让注解生效,就需要开启注解的支持!
    
    
    
 
 
 

9、使用Java的方式配置Spring

我们现在要完全不使用Spring的xml配置了,全权交给Java来做!
 
JavaConfig 是Spring的一个子项目,在Spring4之后,它成为了一个新功能!
Spring5 学习笔记!_第8张图片
 
 
实体类:
package com.kuang.pojo;

import org.springframework.stereotype.Component;

/**
 * @Author panghl
 * @Date 2021/3/18 22:24
 * @Description TODO
 **/
//这里这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中
@Component
public class User {

    private String name;

    public String getName() {
        return name;
    }

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

配置类: 

package com.kuang.config;

import com.kuang.pojo.User;
import org.springframework.context.annotation.*;

/**
 * @Author panghl
 * @Date 2021/3/18 22:25
 * @Description TODO
 **/
//这个也会Spring容器托管,注册到容器中,因为他本来就是一个@Component,
// @Configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
@ComponentScan("com.kuang.pojo")
public class ApplicationConfig2 {

    //注册一个bean,就相当于我们之前写的一个bean标签
    //这个方法的名字,就相当于bean标签中的id属性
    //这个方法的返回值,就相当于bean标签中的class属性
    @Bean
    public User user(){
        User user = new User();
        user.setName("hello");
        return user; //就是返回要注入到bean的对象
    }


}
package com.kuang.config;

import com.kuang.pojo.User;
import org.springframework.context.annotation.*;

/**
 * @Author panghl
 * @Date 2021/3/18 22:25
 * @Description TODO
 **/
//这个也会Spring容器托管,注册到容器中,因为他本来就是一个@Component,
// @Configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
@Import(ApplicationConfig2.class)
public class ApplicationConfig {

}

测试类:

import com.kuang.config.ApplicationConfig;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author panghl
 * @Date 2021/3/18 22:26
 * @Description TODO
 **/
public class MyTest {
    public static void main(String[] args) {
        //如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig 上下文来获取容器,通过配置类的class对象加载
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        User user = (User)applicationContext.getBean("user");

        System.out.println(user.getName());
    }
}

 

这种纯Java的配置方式,在SpringBoot随处可见!
 
 

 

10、代理模式

为什么要学习代理模式?因为这就是SpringAOP的底层! 【SpringAOP 和SpringMVC】
 
 
代理模式的分类:
  • 静态代理
  • 动态代理
Spring5 学习笔记!_第9张图片
 
 
 

10.1、静态代理

角色分析:
  • 抽象角色:一般会使用接口或者抽象类来解决
package com.panghl.demo1;

/**
 * @Author panghl
 * @Date 2021/3/18 22:56
 * @Version 1.0
 * @Description 租房
 **/
public interface Rent {

    public void rent();
}
  • 真实角色:被代理的角色
package com.panghl.demo1;

/**
 * @Author panghl
 * @Date 2021/3/18 22:56
 * @Description 房东
 **/
public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租");
    }
}
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
package com.panghl.demo1;

/**
 * @Author panghl
 * @Date 2021/3/18 22:59
 * @Description TODO
 **/
public class Proxy implements Rent {

    private Host host;

    public Proxy(Host host) {
        this.host = host;
    }

    public Proxy() {
    }

    @Override
    public void rent() {
        seeHouse();
        host.rent();
        fare();
        sign();
    }

    //看房
    public void seeHouse(){
        System.out.println("中介带你看房");
    }

    //收中介费
    public void fare(){
        System.out.println("收中介费");
    }

    //签合同
    public void sign(){
        System.out.println("中介签合同");
    }

}
  • 客户:访问代理对象的人
package com.panghl.demo1;

/**
 * @Author panghl
 * @Date 2021/3/18 22:58
 * @Description TODO
 **/
public class Client {
    public static void main(String[] args) {
        //房东要租房子
        Host host = new Host();
        //代理,中介带房东租房子,但是呢?代理角色一般会有些附属操作
        Proxy proxy = new Proxy(host);

        //你不用面对房东,直接找中介租房即可!
        proxy.rent();


    }
}
 

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!,不用去关注一些公共的业务
  • 公共业务就交给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!

缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍 ~ 开发效率会变低~
 

10.2、加深理解

package com.panghl.demo2;

/**
 * @Author panghl
 * @Date 2021/3/18 23:08
 * @Description TODO
 **/
//接口 - 抽象角色
public interface UserService {
    public void add();
    public void edit();
    public void delete();
    public void select();
}

 

package com.panghl.demo2;

/**
 * @Author panghl
 * @Date 2021/3/18 23:08
 * @Description TODO
 **/
//真实对象
public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加用户");
    }

    @Override
    public void edit() {
        System.out.println("修改用户");
    }

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

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

    //改动原有的业务代码,在公司中是大忌
}

 

package com.panghl.demo2;

/**
 * @Author panghl
 * @Date 2021/3/18 23:10
 * @Description TODO
 **/
public class UserServiceProxy implements UserService {

    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }


    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void edit() {
        log("edit");
        userService.edit();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void select() {
        log("select");
        userService.select();
    }

    public void log(String msg){
        System.out.println("打印了日志--使用了"+msg+"方法");
    }
}

 

package com.panghl.demo2;

/**
 * @Author panghl
 * @Date 2021/3/18 23:09
 * @Description TODO
 **/
public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService =new UserServiceImpl();

        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);


        proxy.add();
        proxy.edit();
        proxy.delete();
        proxy.select();
    }
}

聊聊AOP:

Spring5 学习笔记!_第10张图片
 
 
 

10.3、动态代理

 
  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的!
  • 动态代理分为俩大类:基于接口的动态代理,基于类的动态代理
    • 基于接口---JDK动态代理 【我们在这里使用】
    • 基于类---cglib
    • java字节码实现:javassist
 
需要了解两个类:Proxy:代理 ,InvocationHandler:调用处理程序
 
 
代理角色:
package com.panghl.demo03;

/**
 * @Author panghl
 * @Date 2021/3/18 22:56
 * @Version 1.0
 * @Description 租房
 **/
public interface Rent {

    public void rent();
}
 

真实角色:

package com.panghl.demo03;

/**
 * @Author panghl
 * @Date 2021/3/18 22:56
 * @Description 房东
 **/
public class Host implements Rent {
    @Override
    public void rent() {
        System.out.println("房东要出租");
    }
}

自动生成代理类!

package com.panghl.demo03;

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

/**
 * @Author panghl
 * @Date 2021/3/20 11:15
 * @Description TODO
 **/
//自动生成代理类!
public class ProxyInvocationHandler implements InvocationHandler {

//被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

    //生成得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
    }

    //处理代理实例,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        //动态代理的本质,就是使用反射机制实现
        Object result = method.invoke(rent, args);
        fare();
        return result;
    }

    public void seeHouse(){
        System.out.println("中介看房了");
    }

    public void fare(){
        System.out.println("收中介费");
    }
}

 

 

动态代理的好处:

  • 可以使真实角色的操作更加纯粹!,不用去关注一些公共的业务
  • 公共业务就交给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!
  • 一个动态代理类代理的是一个接口,一般都是对应的一类业务!
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!
 
 
 

11、AOP

11.1、什么是AOP

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

Spring5 学习笔记!_第11张图片

 

11.2、Aop在Spring中的作用

提供声明式事务;允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等...
  • 切面(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 切入点(PointCut):切面通知执行的"地点"的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。

Spring5 学习笔记!_第12张图片

 

Spring5 学习笔记!_第13张图片

 

11.3、使用Spring实现AOP

【重点】使用AOP织入,需要导入一个依赖包
        
            org.aspectj
            aspectjweaver
            1.9.4
        

 

方式一:使用Spring的API接口【主要SpringAPI接口实现】

 

package com.panghl.service;

/**
 * @Author panghl
 * @Date 2021/3/18 23:08
 * @Description TODO
 **/
//接口 - 抽象角色
public interface UserService {
    public int add();
    public int edit();
    public int delete();
    public int select();
}

 

package com.panghl.service;

/**
 * @Author panghl
 * @Date 2021/3/18 23:08
 * @Description TODO
 **/
//真实对象
public class UserServiceImpl implements UserService{
    @Override
    public int add() {
        System.out.println("增加用户");
        return 1;
    }

    @Override
    public int edit() {
        System.out.println("修改用户");
        return 1;
    }

    @Override
    public int delete() {
        System.out.println("删除用户");
        return 1;
    }

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

    //改动原有的业务代码,在公司中是大忌
}
package com.panghl.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * @Author panghl
 * @Date 2021/3/20 11:57
 * @Description TODO
 **/
public class Log implements MethodBeforeAdvice {

    //method: 要执行的目标对象的方法
    //args:参数
    //target:目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}

 

package com.panghl.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

/**
 * @Author panghl
 * @Date 2021/3/20 12:04
 * @Description TODO
 **/
public class AfterLog implements AfterReturningAdvice {

    //returnValue;返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
    }

}



    

    
    
    
    


    
    
        
        

        
        
        
    

import com.panghl.service.UserService;
import com.panghl.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author panghl
 * @Date 2021/3/20 12:15
 * @Description TODO
 **/
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //动态代理代理的是接口
        UserService userService = (UserService)context.getBean("userService");

        userService.add();
    }
}

 

方式二:自定义来实现AOP【主要是切面定义】

package com.panghl.diy;

/**
 * @Author panghl
 * @Date 2021/3/20 12:22
 * @Description TODO
 **/
public class DiyPointCut {

    public void before(){
        System.out.println("==========方法执行前=========");
    }

    public void after(){
        System.out.println("==========方法执行后=========");
    }

}



    

    
    
    
    


    










    

    
        
        
            
            
            
            
            
        
    

方式三:注解实现

package com.panghl.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

/**
 * @Author panghl
 * @Date 2021/3/20 14:34
 * @Description 方式三:使用注解方式实现AOP
 **/
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {

    //切入点
    @Pointcut("execution(* com.panghl.service.UserServiceImpl.*(..))")
    public void pointCut(){

    }

    @Before("pointCut()")
    public void before(){
        System.out.println("方法执行前");
    }

    @After("pointCut()")
    public void after(){
        System.out.println("方法执行后");
    }

    //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点;
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("环绕前。。。");

        //获得签名
        System.out.println("signature->:"+joinPoint.getSignature());
        System.out.println("signature->:"+joinPoint.getSignature().getName());

        //执行方法
        Object proceed = joinPoint.proceed();

        System.out.println("环绕后...");

        System.out.println(proceed);
        return proceed;
    }
}

 

12、整合Mybatis

步骤:

 

1、导入相关jar包

  • junit
  • mybatis
  • mysql数据库
  • spring相关的
  • aop织入
  • mybatis-spring【new】

2、编写配置文件

3、测试

 

12.1、回忆mybatis

1、编写实体类

package com.panghl.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author panghl
 * @Date 2021/3/20 15:29
 * @Description TODO
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;


}

2、编写核心配置文件



    
        spring-study
        com.panghl
        1.0-SNAPSHOT
    
    4.0.0

    spring-10-mybatis

    
        
            junit
            junit
            4.12
        
        
            mysql
            mysql-connector-java
            8.0.21
        
        
            org.mybatis
            mybatis
            3.5.2
        
        
            org.mybatis
            mybatis-spring
            2.0.2
        
        
            org.springframework
            spring-webmvc
            5.1.9.RELEASE
        

        
            org.springframework
            spring-jdbc
            5.1.9.RELEASE
        
        
            org.aspectj
            aspectjweaver
            1.9.4
        
        
            org.projectlombok
            lombok
            1.16.10
        
    

    
    
    
        
            
                src/main/resources
                
                    **/*.properties
                    **/*.xml
                
                false
            
            
                src/main/java
                
                    **/*.properties
                    **/*.xml
                
                true
            
        
    

3、编写接口

package com.panghl.mapper;

import com.panghl.pojo.User;

import java.util.List;

/**
 * @Author panghl
 * @Date 2021/3/20 15:32
 * @Version 1.0
 * @Description TODO
 **/
public interface UserMapper {

    public List selectUsers();
}

4、编写Mapper.xml





    
        
    

    
        
            
            
                
                
                
                
            
        
    

    
    

        
    

5、测试

Spring5 学习笔记!_第14张图片

12.2、Mybatis-spring

官网:http://mybatis.org/spring/zh/index.html

什么是 MyBatis-Spring?

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

动机

Spring 2.0 只支持 iBatis 2.0。那么,我们就想将 MyBatis3 的支持添加到 Spring 3.0 中(参见 Spring Jira 中的 问题 )。不幸的是,Spring 3.0 的开发在 MyBatis 3.0 官方发布前就结束了。 由于 Spring 开发团队不想发布一个基于未发布版的 MyBatis 的整合支持,如果要获得 Spring 官方的支持,只能等待下一次的发布了。基于在 Spring 中对 MyBatis 提供支持的兴趣,MyBatis 社区认为,应该开始召集有兴趣参与其中的贡献者们,将对 Spring 的集成作为 MyBatis 的一个社区子项目。

 

1、编写数据源配置

2、SqlSessionFactory

3、sqlSessionTemplate

4、需要给接口加实现类【】

5、将字节写的实现类,注入到Spring中




    

    
        
        
        
        
    

    
        
        
        
        
        
    

    
    
        
        
    

    
    
        
    

6、测试使用即可!

    @Test
    public void springMybatis(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserMapperImpl userMapperIml = (UserMapperImpl)context.getBean("userMapperImpl");
        System.out.println(userMapperIml.selectUsers());
    }
Spring5 学习笔记!_第15张图片
 
 

SqlSessionDaoSupport

 
SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供  SqlSession。调用  getSqlSession() 方法你会得到一个  SqlSessionTemplate,之后可以用于执行 SQL 方法!
 
package com.panghl.mapper;

import com.panghl.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

/**
 * @Author panghl
 * @Date 2021/3/20 16:33
 * @Description TODO
 **/
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List selectUsers() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUsers();
    }
}

    
        
    

 

 

13、声明式事务

1、回顾事务

  • 把一组业务当成一个业务来做;要么都成功,要嘛都事务!
  •  事务在项目开发中,十分的重要,,设计到数据的一致性问题,不能马虎
  • 确保完整性和一致性;

 

事务ACID原则:

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作同一资源,防止数据损坏
  • 持久性
    • 事务一旦提交,无论系统发生什么问题,结果都不会再被影响
 
 

2、spring中的事务管理

  • 声明式事务:AOP

  • 编程式事务:需要在代码中进行事务的管理

实体类:

package com.panghl.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

 UserMapper

package com.panghl.mapper;

import com.panghl.domain.User;

import java.util.List;

/**
 * @Author panghl
 * @Date 2021/3/20 15:32
 * @Version 1.0
 * @Description TODO
 **/
public interface UserMapper {

    public List selectUser();

    public void insert(User user);


    public void deleteById(int id);
}

 




    

    
        insert  into user (id,name,pwd) value(#{id},#{name},#{pwd})
    

    
        deletes from user where id=#{id}
    

 

package com.panghl.mapper;

import com.panghl.domain.User;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

/**
 * @Author panghl
 * @Date 2021/3/20 18:29
 * @Description TODO
 **/
public class UserMapperImpl3 extends SqlSessionDaoSupport implements UserMapper {

    @Override
    public List selectUser() {
        User user = new User(10,"ddd","ddd");
        insert(user);
        deleteById(10);
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }

    @Override
    public void insert(User user) {
        getSqlSession().getMapper(UserMapper.class).insert(user);
    }

    @Override
    public void deleteById(int id) {
        getSqlSession().getMapper(UserMapper.class).deleteById(id);
    }
}

mybatis配置文件:





    
        
    


spring配置文件: 




    

    
        
        
        
        
    

    
        
        
        
        
        
    



    
    
        
    

    
    
    
        
        
        
            
        
    

    
    
        
        

    

    
        
    


 

测试:


import com.panghl.mapper.UserMapper;
import com.panghl.mapper.UserMapperImpl3;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


/**
 * @Author panghl
 * @Date 2021/3/20 15:38
 * @Description TODO
 **/
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserMapper userMapperIml = (UserMapper)context.getBean("userDao");
        System.out.println(userMapperIml.selectUser());
    }

}

 

Spring声明式事务@Transactional 详解,事务隔离级别和传播行为 :https://blog.csdn.net/qq_45441466/article/details/115035741

 

Spring5 学习笔记!_第16张图片

 

思考:

为什么需要事务?

  • 如果不配置事务,可能存在数据提交不一致的的情况下;
  • 如果我们不在Spring中去配置声明式事务,我们就需要在代码中手动配置事务!
  • 事务在项目的开发中十分重要, 涉及到数据的一致性和完整性问题,不容马虎!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

你可能感兴趣的:(SSM,spring,java,ioc)