Spring5,最全教程,带你认识IOC容器和AOP切面

2023年 9月 12日 186.9k 0

1.Spring

1.1简介

  • Spring:春天----->给软件行业带来了春天!

  • 2002,首次推出了Spring框架的雏形:interface21框架!

  • Spring框架即以inteface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。

  • Rod Johnson,SpringFramework创始人,著名作者,很难想象Rod Johnson的学历,真的让人大吃一惊,他是悉尼大学博士,然而他的专业却不是计算机,而是音乐家

  • spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!

  • SSH :Struct2 + Spring + Hibernate

  • SSM:SpringMvc + Spring + Mybatis

官网:spring.io/projects/sp…

官方下载地址repo.spring.io/ui/native/r…

GitHub:github.com/spring-proj…

Maven:如果我们只导入spring的包有很多需要一个一个导入,我们可以导入更庞大的mvc的包,里面包含了spring



    org.springframework
    spring-webmvc
    5.2.0.RELEASE

1.2优点

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

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

1.3组成

七大模块组成

1.4扩展

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

image-20220228104650531

  • SpringBoot

    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速的开发单个微服务
    • 预定大于配置
  • SpringCloud

    • SpringCloud是基于SpringBoot实现的

因为现在大多数公司都在使用SpringBoot进行快速开发,学会SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用!

弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称配置地狱!

2.IOC理论推导

原来的架构

  • UserDao 接口
  • UserDaolmpl 实现类
  • UserService 业务接口
  • UserServiceImpl 业务实现类
  • 在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!如果程序代码量十分大,修改一次的成本十分昂贵!

    image-20220228150752177

    我们使用一个set接口实现,已经发生了革命性的变化

    private UserDao userDao;
    
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao; 
    }
    
    • 之前,程序是主动创建对象!控制权在程序员手上
    • 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!

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

    image-20220228150803721

    在我们原来写的代码,每个模块都相互依赖,一个模块出错,全部都运行不了

    image-20220228151643990

    我们使用IOC容器后的代码,由我们ICO来管理这些模块

    image-20220228151731944

    未来的代码,每个模块都单独运行,互不影响

    image-20220228151755239

    IOC本质

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

    采用xml方式配置Bean的时候,Bean的定义信息和实现分离的,而采用注解的方式可以吧两者合为一体,Bean的定义信息直接以注解的新式定义在实现类中,从而达到了零配置的目的(自动装配)。

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

    3.HelloSpring

    给对象赋值

    pojo

    package com.xh.pojo;
    
    public class Hello {
        private String hello;
    
        public String getHello() {
            return hello;
        }
    
        public void setHello(String hello) {
            this.hello = hello;
        }
    
        @Override
        public String toString() {
            return "Hello{" +
                    "hello='" + hello + ''' +
                    '}';
        }
    }
    

    beans.xml

    
    
    
    
            
                
            
    
    

    测试

    @Test
    public void test1(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Hello hello = (Hello) context.getBean("Hello");
        System.out.println(hello.toString());
    }
    

    赋值对象

    这里指的是,我们通过xml的方式,给serviceImpl中的set方法注入dao的对象

    image-20220228164513496

    dao

    public interface UserDao {
        void getuser();
    }
    

    dao实现类

    package com.xc.dao;
    
    public class MysqlDaoImpl implements UserDao{
        public void getuser() {
            System.out.println("Mysql");
        }
    }
    
    package com.xc.dao;
    
    public class OracleImpl implements UserDao{
        public void getuser() {
            System.out.println("oracle");
        }
    }
    

    service

    package com.xc.service;
    
    public interface UserService {
        void getuser();
    }
    

    service实现类

    package com.xc.service;
    
    import com.xc.dao.UserDao;
    
    public class UserServiceImpl implements UserService{
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        public void getuser() {
            userDao.getuser();
        }
    }
    

    beans.xml

    
    
    
        
        
        
        
    
            
        
    
    
    

    测试

    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserService userservice = (UserService) context.getBean("userservice");
        userservice.getuser();
    }
    

    image-20220228164143899

    4.IOC创建对象的方式

    使用IOC创建对象的时候一定要定义构造器

    通过IOC创建对象流程:

    我们在new ClassPathXmlApplicatonContext(beans.xml)

    的时候通过无参构造已经将我们配置文件中的bean创建到容器中(new 对象)实例化了

    通过有参构造创建对象

    
    
    
    
        
            
        
    
    
        
            
        
    
    
        
            
        
    

    一共有四中方法通过IOC创建对象

    总结

    在配置文件加载的时候,容器中管理的对象就已经初始化了(new 对象)!

    5.Spring配置

    别名

    
    
    
        
    

    Bean的配置

    
        
            
        
    

    import

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

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

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

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

    image-20220228190949917

    6.DI依赖注入

    1.构造器注入

    详情看4.IOC创建对象方式

    2.Set方式注入【重点】

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

    【环境搭建】

  • 复杂类型

    package com.kuang.pojo;
    
    public class Address {
        private String address;
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    
  • 证实测试对象

  • package com.kuang.pojo;
    
    
    import java.util.*;
    
    public class Student {
        private String name;
        private Address address;
        private String[] books;
        private List hobbys;
        private Map car;
        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 getCar() {
            return car;
        }
    
        public void setCar(Map car) {
            this.car = car;
        }
    
        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;
        }
    
        @Override
        public java.lang.String toString() {
            return "Student{" +
                    "name=" + name +
                    ", address=" + address +
                    ", books=" + Arrays.toString(books) +
                    ", hobbys=" + hobbys +
                    ", car=" + car +
                    ", games=" + games +
                    ", wife=" + wife +
                    ", info=" + info +
                    '}';
        }
    }
    

    ApplicationContext.xml

    
    
    
        
            
        
    
    
        
    
            
    
            
    
            
                
                    语文
                    数学
                    英语
                
            
            
            
                
                    苹果
                    香蕉
                    西瓜
                
            
    
            
                
                    
                    
                
            
    
            
                
                    湖北
                    北京
                    上海
                
            
    
            
                
                    武汉
                    菏泽
                    郑州
                
            
    
            
                
            
    
        
    
    
    

    测试

    import com.kuang.pojo.Student;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            Student student = (Student) context.getBean("student");
            System.out.println(student.getName());
        }
    }
    

    3.拓展方式注入

    C命名空间注入和B命名空间注入

    image-20220228200718046

    P命名空间注入

    image-20220228195231825

    
    
    
    
    
        
        
    
    

    image-20220228195612396

    C命名空间注入

    
    
    
    
        
    
    

    注意点

    7.Bean的作用域

    image-20220301085932364

    • 单例模式(singleton)容器里面只存在一个相同的对象,用户多次new这个对象,都是拿的容器中同一个

      
      

      image-20220301090720230

    • 原型模式(prototype)用户new多少个对象,就创建多少个对象

      
      

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c2Z3OGk9-1659404482191)(img.jyxcwl.cn/image-20220…)]

    7.Bean自动装配

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

    在Spring中有三种装配的方式

    • 在xml中显示的配置
    • 在java中显示配置
    • 隐式的自动自动装配bean【重要】

    测试

  • 环境搭建
    • 一个人有两个宠物!
    package com.kuang.pojo;
    
    public class Cat {
        public void shot(){
            System.out.println("miao~");
        }
    }
    
    package com.kuang.pojo;
    
    public class Dog {
        public void shot(){
            System.out.println("wang~");
        }
    }
    
    package com.kuang.pojo;
    
    public class person {
        private Cat cat;
        private Dog dog;
        private String name;
    
        @Override
        public String toString() {
            return "person{" +
                    "cat=" + cat +
                    ", dog=" + dog +
                    ", name='" + name + ''' +
                    '}';
        }
    
        public Cat getCat() {
            return cat;
        }
    
        public void setCat(Cat cat) {
            this.cat = cat;
        }
    
        public Dog getDog() {
            return dog;
        }
    
        public void setDog(Dog dog) {
            this.dog = dog;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
    
    
            
            
    
        
            
            
            
        
    
    
    
    import com.kuang.pojo.person;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class test {
        @Test
        public void test1(){
            ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
            person person = (com.kuang.pojo.person) context.getBean("person");
            //cat对象.方法
            person.getCat().shot();
        }
    }
    
    miao~
    

    自动装配(Autowire)

    上面那些通过propert方式使用ref指定一个引用对象,很麻烦,所以就有了自动装配,bean自动帮我们设置ref中的引用对象

    方式一

    使用byname

    
    
    
            
            
    
        
            
        
    
    
    
  • 这里使用byname表示,
  • 这里需要绑定的bean id 必须唯一
  • 方式二

    使用bytype

    
    
    
            
            
    
        
            
        
    
    
    
  • 这里bytype表示,绑定的是class类型,这里bean的id可以不要,但是class必须要唯一
  • 总结

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

    注解自动装配

    @Autowired

    他的功能跟我们autowire="bytype"执行的效果是一样的,

    先更具byname来设置,如果byname找不到,那么就bytype寻找class

    以前我们使用自动装配

    image-20220301101608780

    现在注解装配,更简洁

    image-20220301101623576

    image-20220301101644220

    @Resource

    也是一个自动装配的注解

    image-20220301101952515

    小结

    @Resource和@Autowired区别:

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

    8.spring使用注解开发

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KXAts48z-1659404482196)(C:Users杨贵强AppDataRoamingTyporatypora-user-imagesimage-20220301111000405.png)]

    在使用注解需要导入 context约束,增加注解支持

    
    
    
    
        
    
        
    
    

    bean注解注入容器

    pojo

    package com.kuang.dao;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    
    @Component //等价于 //    
    public class User {
        private String name="星辰";
    }
    

    test

    import com.kuang.dao.User;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class test {
        @Test
        public void test1(){
            ApplicationContext Context = new ClassPathXmlApplicationContext("applicationcontext.xml");
            User user = (User) Context.getBean("user");
            System.out.println(user.getName());
        }
    }
    

    image-20220301112022319

    对象属性如何注入

    package com.kuang.dao;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    
    @Component //等价于 //    
    public class User {
    
        @Value("星辰")  // 等价于 
        private String name;
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    import com.kuang.dao.User;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class test {
        @Test
        public void test1(){
            ApplicationContext Context = new ClassPathXmlApplicationContext("applicationcontext.xml");
            User user = (User) Context.getBean("user");
            System.out.println(user.getName());
        }
    }
    

    衍生注解

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

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

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

    自动装配配置

    @Autowired:自动装配通过类型然后名称
    	如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
    @Nullable	:字段标记了这个注解,说明这个字段可以为null
    @Resource	:自动装配通过名称然后类型 【跟Autowired顺序相反】
    

    作用域

    package com.kuang.dao;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Repository;
    
    
    @Component //等价于 //    
    @Scope("prototype") //单例singleton,原型prototype
    public class User {
    
        private String name="星辰";
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    小结

    xml与注解:

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

    xml与注解最佳实践:

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

    9.使用java的方式配置Spring

    我们现在要完全不使用spring的xml配置了,全部交给java来做

    JavaConfig是spring的一个子项目,在spring4之后,成为了一个核心功能

    pojo

    package com.kuang.pojo;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component   //等价于 
    public class User {
        @Value("星辰")
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    configuration

    package com.kuang.config;
    
    import com.kuang.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    
    //这个也会spring容器托管,注册到容器中,因为他本来就是一个@Coponent
    //@Config代表这是一个配置类,就和我们之前看的beans.xml
    @Configuration
    public class Config1 {
    
        //注册一个bean,就相当于我们之前写的一个bean标签
        //这个方法的名字,就相当于bean标签中的id属性
        //这个方法的返回值,就相当于bean标签中的class属性
        @Bean
        public User getuser(){
            return new User();//就说返回要注入到bean的对象
        }
        
        /*
        
        
        	
        
        
        
        	
       	
        */ 
            
    
    }
    

    测试

    import com.kuang.config.Config1;
    import com.kuang.pojo.User;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Test {
        @org.junit.Test
        public void test1(){
            ApplicationContext context = new AnnotationConfigApplicationContext(Config1.class);
            User getuser = (User) context.getBean("getuser");
            System.out.println(getuser.getName());
        }
    }
    

    这种纯java的配置方式,在springboot中随处可见

    10.AOP

    静态代理

    租房流程

    image-20220301164707263

    好处:

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

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

    角色分析

    • 抽象角色:一般会使用接口或者抽象类来解决
    • 真实角色:被代理的角色
    • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作【例如在原有的方法上,增加日志】
    • 客户:访问代理对象的人!

    没有引入代理

    image-20220301165437833

    引入代理

    抽象角色:房子

    package com.kuang.jingtai;
    
    public interface zhufang {
        //共同租房的形式
        void zhufang();
    }
    

    房东

    package com.kuang.jingtai;
    
    public class fangdong implements zhufang{
        //房东实现租房的接口
        public void zhufang() {
            System.out.println("成功租到房子");
        }
    }
    

    代理

    package com.kuang.jingtai;
    
    public class daili implements zhufang{
        private fangdong fangdong;
        public daili() {
        }
    
        public daili(com.kuang.jingtai.fangdong fangdong) {
            this.fangdong = fangdong;
        }
    
        //找中介租房的时候,
        public void zhufang() {
            //代理可以做一些附加的格外事情,
            //交钱
            jiaoqian();
            //签合同
            hetong();
            //用户交完钱后和签完合同后,直接吧房东的房子给用户
            fangdong.zhufang();
        }
    
        public void jiaoqian(){
            System.out.println("交钱");
        }
        public void hetong(){
            System.out.println("签合同");
        }
    
    }
    

    package com.kuang.jingtai;
    
    public class wo {
        public static void main(String[] args) {
            //获取我们想租房的房东
            fangdong fangdong = new fangdong();
            //获取我们的中介
            daili daili = new daili(fangdong);
            //通过代理进行租房
            daili.zhufang();
        }
    }
    

    加深理解

    我们想在原因的代码功能基础上增加日志功能!

    package com.kuang.demo1;
    
    //业务接口
    public interface service {
        void add();
        void delete();
        void update();
        void query();
    }
    
    package com.kuang.demo1;
    
    //业务实现类
    public class serviceImpl implements service{
    
        public void add() {
            System.out.println("新增一个用户");
        }
    
        public void delete() {
            System.out.println("清除一个用户");
        }
    
        public void update() {
            System.out.println("修改一个用户");
        }
    
        public void query() {
            System.out.println("查询一个用户");
        }
    }
    
    package com.kuang.demo1;
    
    //代理类
    public class dailiImpl implements service{
        private serviceImpl serviceimpl;
    
        public void setServiceimpl(serviceImpl serviceimpl) {
            this.serviceimpl = serviceimpl;
        }
    
    
        //我们可以代理业务实现,增加日志功能
        public void add() {
            log("add");
            serviceimpl.add();
        }
    
        public void delete() {
            log("delete");
            serviceimpl.delete();
        }
    
        public void update() {
            log("update");
            serviceimpl.update();
        }
    
        public void query() {
            log("query");
            serviceimpl.query();
        }
    
        public void log(String msg){
            System.out.println("执行了"+msg+"方法");
        }
    }
    
    package com.kuang.demo1;
    
    public class test {
        public static void main(String[] args) {
            //真实对象
            serviceImpl service = new serviceImpl();
            //代理对象
            dailiImpl daili = new dailiImpl();
            //通过set方法代理我们真实对象
            daili.setServiceimpl(service);
            //通过代理调用方法
            daili.query();
        }
    }
    

    动态代理

    package com.kuang.dongtai;
    
    public interface Host {
        void zhufang();
    }
    
    package com.kuang.dongtai;
    
    public class fangdong implements Host{
        public void zhufang() {
            System.out.println("成功出租房子");
        }
    }
    
    package com.kuang.dongtai;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class invocationHandler implements InvocationHandler {
    
        //需要被代理的接口
        private Host host;
    
        public void setHost(Host host) {
            this.host = host;
        }
    
        //程序自动生成代理类
        public Object getProxy(){
           return Proxy.newProxyInstance(this.getClass().getClassLoader(), host.getClass().getInterfaces(),this);
        }
    
        //处理代理实例,并返回结果
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //动态的本质就是通过反射机制实现的
            Object invoke = method.invoke(host, args);
            return invoke;
        }
    }
    
    package com.kuang.dongtai;
    
    public class test {
        public static void main(String[] args) {
            fangdong fangdong = new fangdong();
            invocationHandler invocationHandler = new invocationHandler();
            invocationHandler.setHost(fangdong);
            fangdong proxy =(fangdong)invocationHandler.getProxy();
            proxy.zhufang();
        }
    }
    

    实现AOP日志

    AOP底层是基于动态代理实现的,动态代理的是接口

    
            
            
                org.aspectj
                aspectjweaver
                1.9.4
            
    

    image-20220302111209238

    image-20220302111313998

    image-20220302111344669

    方式一

    使用Spring自带的API接口实现

    接口

    package com.kuang.service;
    
    public interface UserService {
        void add();
        void delete();
        void update();
        void select();
    }
    

    实现类

    package com.kuang.service;
    
    public class UserServiceImpl implements UserService{
        public void add() {
            System.out.println("增加了一个用户");
        }
    
        public void delete() {
            System.out.println("清除了一个用户");
        }
    
        public void update() {
            System.out.println("修改了一个用户");
        }
    
        public void select() {
            System.out.println("查询了一个用户");
        }
    }
    

    日志

    前置

    package com.kuang.aop;
    
    import org.springframework.aop.BeforeAdvice;
    import org.springframework.aop.MethodBeforeAdvice;
    
    import java.lang.reflect.Method;
    
    public class BeforeLog implements MethodBeforeAdvice {
    
        //前置增强
        //method:方法
        //objects:参数
        //o:目标对象
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println(o.getClass().getName()+"执行了"+method.getName()+"方法");
        }
    }
    

    后置

    package com.kuang.aop;
    
    import org.springframework.aop.AfterReturningAdvice;
    
    import java.lang.reflect.Method;
    
    public class AfterAdviceLog implements AfterReturningAdvice {
        //后置增强
        //o:返回值
        //method:方法
        //objects:参数
        //o1:目标对象
        public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
            System.out.println(method.getName()+"执行完毕"+"返回值"+o);
        }
    }
    

    配置类

    
    
    
        
        
        
        
    
    
        
    
            
    
    
            
            
        
    
    
    
    

    execution表达式

    image-20220302104942338

    方式二

    自定义切面类,给写入点通知

    自定义切面

    package com.kuang.utils;
    
    public class log {
        public void Before(){
            System.out.println("执行方法前");
        }
        public void after(){
            System.out.println("执行方法后");
        }
    }
    

    自定义切面

        
    
            
    
                
    
                
                
            
        
    

    总结:

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

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

    使用注解实现

    package com.kuang.utils;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    //使用注解配置AOP
    
    @Aspect//标志这是一个切面
    public class anocation {
    
    //    前置增强
        @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
        public void Before(){
            System.out.println("方法执行前");
        }
    //    后置增强
        @After("execution(* com.kuang.service.UserServiceImpl.*(..))")
        public void After(){
            System.out.println("方法执行后");
        }
    
        //环绕增强
        @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
        public void around(ProceedingJoinPoint point) throws Throwable {
            System.out.println("===环绕前===");
            Object proceed = point.proceed();//执行原本业务方法
            System.out.println("===环绕后===");
        }
    
    }
    
    

    applicationcontext.xml

    
        
    

    结果

    ===环绕前===
    方法执行前
    增加了一个用户
    ===环绕后===
    方法执行后
    

    11.整合Mybatis

    步骤:

  • 导入相关依赖包
    • junt
    • springmvc
    • aspectjweaver
    • mysql
    • mybatis
    • spring-jdbc
    • mybatis-spring
    • lombok
  • 编写xml配置文件
    • db.properties【数据库信息】
    • mybatis-config.xml【mybatis配置】
    • applicationcontext.xml【Spring配置】
  • 测试
  • 回忆Mybatis

    pojo

    package com.kuang.pojo;
    
    import lombok.Data;
    
    @Data
    public class user {
        private int id;
        private String name;
        private String password;
    }
    

    mapper

    package com.kuang.dao;
    
    import com.kuang.pojo.user;
    
    import java.util.List;
    
    public interface UserMapper {
        List queryUserList();
    }
    

    mybatis工具类

    package com.kuang.utils;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.InputStream;
    
    public class MybatisUtils {
        private static SqlSessionFactory sqlSessionFactory;
    
        static {
            try {
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
            }catch (Exception e){
                e.toString();
            }
        }
    
        public static SqlSession getSqlSession(){
           return sqlSessionFactory.openSession();
        }
    }
    

    数据库信息

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis
    username=root
    password=0000
    

    mybatis配置信息

    
    
    
    
        
    
    
        
            
        
    
        
            
                
                
                    
                    
                    
                    
                
            
        
    
    
        
            
        
    
    
    

    test

    import com.kuang.dao.UserMapper;
    import com.kuang.pojo.user;
    import com.kuang.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    
    import java.util.List;
    
    public class Test {
        @org.junit.Test
        public void test1(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List users = mapper.queryUserList();
            for (user user : users) {
                System.out.println(user);
            }
            sqlSession.close();
        }
    }
    

    image-20220302151851591

    整合方式一

    image-20220302162643201

    pojo

    package com.kuang.pojo;
    
    import lombok.Data;
    
    @Data
    public class user {
        private int id;
        private String name;
        private String password;
    }
    

    UserMapper

    package com.kuang.dao;
    
    import com.kuang.pojo.user;
    
    import java.util.List;
    
    public interface UserMapper {
        List queryUserList();
    }
    

    UsermapperImpl

    package com.kuang.dao;
    
    import com.kuang.pojo.user;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionTemplate;
    
    import java.util.List;
    
    public class UserMapperImpl implements UserMapper{
    //    构造SqlSession
        private SqlSessionTemplate sqlSession;
    //这里spring中的bean通过set方法进行注入
        public void setSqlSession(SqlSessionTemplate sqlSession) {
            this.sqlSession = sqlSession;
        }
    
        public List queryUserList() {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            return mapper.queryUserList();
        }
    }
    

    Usermapper.xml

    
    
    
    
    
        
            
        
    
        
            select * from user
        
    
    

    mybatis配置

    
    
    
    
    
        
            
        
        
    
    
    
    
    
    
        
            
        
    
    
    

    ApplicationContext.xml

    
    
    
    
        
            
            
            
            
        
    
    
        
            
    
            
        
    
    
        
            
        
    
    
    
        
            
        
    
    
    

    测试

    import com.kuang.dao.UserMapper;
    import com.kuang.pojo.user;
    import com.kuang.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.List;
    
    public class Test {
        @org.junit.Test
        public void test1(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
            UserMapper userMapperImpl = (UserMapper) applicationContext.getBean("UserMapperImpl");
            List users = userMapperImpl.queryUserList();
            for (user user : users) {
                System.out.println(user);
            }
        }
    }
    

    image-20220302162631036

    方式二

    SqlSessionDaoSupport

    package com.kuang.dao;
    
    import com.kuang.pojo.user;
    import org.apache.ibatis.session.SqlSession;
    import org.mybatis.spring.support.SqlSessionDaoSupport;
    
    import java.util.List;
    
    //通过基础SqlSessionDaoSupport简化代码,不用手动set方法去设置sqlSession
    public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    
        public List queryUserList() {
    
            SqlSession sqlSession = getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            return mapper.queryUserList();
    
    //        return getSqlSession().getMapper(UserMapper.class).queryUserList();
    
        }
    }
    
    
        
            
        
    

    12.声明式事务

    在不改变原有的代码,实现解耦,配置事务

    spring中不允许手动回滚,需要配置事务的bean进行自动事务

    回顾事务

    • 要么都成功,要么都失败!
    • 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎
    • 确保完整性和一致性

    事务的ACID原则

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

    Spring中的事务管理

    pojo

    package com.kuang.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String password;
    }
    

    dao

    package com.kuang.dao;
    
    import com.kuang.pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
        List queryUserList();
        int addUser(User user);
        int deleteUser(int id);
    }
    

    impl

    package com.kuang.dao;
    
    import com.kuang.pojo.User;
    import org.mybatis.spring.SqlSessionTemplate;
    
    import java.util.List;
    
    public class UserMapperImpl implements UserMapper{
        private SqlSessionTemplate SqlSession;
    
        public void setSqlSession(SqlSessionTemplate sqlSession) {
            SqlSession = sqlSession;
        }
    
        public List queryUserList() {
    
            UserMapper mapper = SqlSession.getMapper(UserMapper.class);
            try {
                mapper.addUser(new User(6,"xc","123456"));
                mapper.deleteUser(5);
                SqlSession.commit();
            }catch (Exception e){
                SqlSession.rollback();
            }
            return mapper.queryUserList();
        }
    
        public int addUser(User user) {
            return 0;
        }
    
        public int deleteUser(int id) {
            return 0;
        }
    }
    

    mapper.xml

    
    
    
        
            
        
    
        
            select * from user
        
    
        
            insert into user set id=#{id},name=#{name},pwd=#{password}
        
    
    
        
            delet user where id=#{id}
        
    
    
    
    

    mybatis-config.xml

    
    
    
        
            
        
    
    

    applicationcontext.xml

    
    
    
        
            
            
            
            
        
    
        
        
            
            
        
    
        
        
            
        
    
        
        
            
        
    
    
        
            
        
    
    
    
        
    
    
            
                
                
                
                
    
                
            
        
    
    
        
            
            
            
            
        
    
    
    

    test

    import com.kuang.dao.UserMapper;
    import com.kuang.pojo.User;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.util.List;
    
    public class test {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserMapper userMapperImpl = (UserMapper) context.getBean("UserMapperImpl");
            List users = userMapperImpl.queryUserList();
            for (User user : users) {
                System.out.println(user);
            }
        }
    }
    

    image-20220302205700245

    报错,但是spring通过aop切面执行了事务。数据库数据没有改变

    image-20220302205738247

    思考

    为什么需要事务?

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

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论