Spring笔记

Spring笔记

1. Spring概述(了解)

1.1 Spring是什么

  • Spring是分层的JavaSE/EE应用full-stack轻量级开源框架

  • 以IOC(控制反转)和AOP(面向切面编程)为内核,提供了展现层SpringMVC和持久层 Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多的著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架

  • 使服务器开发更加简单

  • <!--导入springMVC框架-->
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.2.RELEASE</version>
            </dependency>
        </dependencies>
    
  • <!--导入spring jdbc-->
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.2.2.RELEASE</version>
            </dependency>
        </dependencies>
    

1.2 Spring的发展历程

  • 2004 年 03 月,1.0 版发布。
  • 2006 年 10 月,2.0 版发布。
  • 2007 年 11 月,更名为 SpringSource,同时发布了 Spring 2.5。
  • 2009 年 12 月,Spring 3.0 发布。
  • 2013 年 12 月,Pivotal 宣布发布 Spring 框架 4.0。
  • 2017 年 09 月,Spring 5.0 发布。

1.3 Spring的优势

  • 非侵入式设计:Spring是一种非侵入式(non-invasive)框架,它可以使应用程序代码对框架的依赖最小化。
  • 方便解耦、简化开发:Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器的管理,大大的降低了组件之间的耦合性。
  • 支持AOP:Spring提供了对AOP的支持,它允许将一些通用任务,如安全、事物、日志等进行集中式处理,从而提高了程序的复用性。
  • 支持声明式事务处理:只需要通过配置就可以完成对事物的管理,而无须手动编程。
  • 方便程序的测试:Spring提供了对Junit4的支持,可以通过注解方便的测试Spring程序。
  • 方便集成各种优秀框架:Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如Struts、Hibernate、MyBatis、Quartz等)的直接支持。
  • 降低Jave EE API的使用难度:Spring对Java EE开发中非常难用的一些API(如JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低。
  • IOC(控制反转)和AOP(面向切面编程)

1.4 Spring的体系结构

1.5 扩展

  • 现代化的java开发,就是基于spring开发
  • Spring Boot
    • 一个快速开发的脚手架
    • 基于Spring Boot可以快速的开发单个微服务
    • 约定大于配置
  • Spring Cloud
    • Spring Cloud是基于Spring Boot实现的

2. IOC理论推导

2.1 IOC理论

  • UserDao接口

    public interface UserDao {
        void getUser();
    }
    
  • UserDaoImpl实现类

    public class UserDaoImpl implements UserDao {
        public void getUser(){
            System.out.println("默认获取用户的数据");
        }
    }
    
  • UserService业务接口

    public interface UserService {
        void getUser();
    }
    
  • UserServiceImpl业务实现类

    public class UserServiceImpl implements UserService {
        private UserDao userDao;
    
        //利用set进行动态实现值的注入
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        public void getUser() {
            userDao.getUser();
        }
    }
    
  • 测试

    public class MyTest {
        public static void main(String[] args) {
            //用户实际调用的是业务层,dao层他们不需要接触
            UserService userService = new UserServiceImpl();
            userService.setUserDao(new UserDaoImpl());
    
            userService.getUser();
        }
    }
    
  • 测试结果

  • 在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码,如果修改代码非常多,则代价很大

  • 控制反转:之前的程序是主动创建对象,控制权在程序员手上

  • 使用了set注入后,程序不具有主动性,而是变成了被动的接受对象!

  • 程序元不用再去管理对象的创建,系统的耦合性大大降低,可以更加专注在业务的实现上!这是IOC的原型

2.2 IOC本质

  • 控制反转IOC是一种设计思想,DI(依赖注入)是实现IOC的一种方法

  • 面向对象编程,对象的创建与对象间的依赖关系完全由硬编码在程序中,对象的创建由程序自己控制

  • 控制反转后的对象的创建转移给第三方,其实就是获得依赖对象的方式反转了

  • IOC是Spring框架的核心内容,使用多种方式完美的实现IOC,可以使用xml配置,也可以使用注解,新版本的Spring也可以零配置实现IOC

  • Spring容器在初始化时先读取配置问价你,根据配置文件或者元数据创建与组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象

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

  • 控制反转时一种通过描述(xml或者注解)并通过第三方去生产或者获取特定对象的方式,实现控制反转的时IOC容器,其实现方法时依赖注入(DI)

3. HelloSpring

  • 编写Hello类

    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 + '\'' +
                    '}';
        }
    }
    
  • 编写配置文件(beans.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    
        <!--使用Spring来创建对象,在Spring这些都称为Bean
    
            类型 变量名 = new 类型();
            Hello hello = new Hello();
    
            id = 变量名
            class = new的对象
            property 相当于给对象中的属性赋一个值
    
            ref:引用Spring容器中创建好的对象
            value:具体的值,基本数据类型
        -->
        <bean id="hello" class="com.kuang.pojo.Hello">
            <property name="str" value="Spring"/>
        </bean>
    
    </beans>
    
  • 测试

    public class MyTest {
        public static void main(String[] args) {
            //提供给ApplicationContext构造函数的位置路径是资源字符串,
            // 这些资源字符串使容器可以从各种外部资源(例如本地文件系统,
            // Java CLASSPATH等)加载配置元数据。
    
            //获取Spring的上下文对象
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("beans.xml");
            //我们的对象现在都在Spring中管理,当我们需要使用的时候,直接取出来就可以了
            Hello hello = (Hello) context.getBean("hello");
            System.out.println(hello.toString());
        }
    
    }
    

4. IOC创建对象的方式

  • 使用无参构造创建对象

  • 假设使用有参构造创建对象

    • 下标赋值

    • <!--第一种:下标赋值-->
          <bean id="hello" class="com.kuang.pojo.Hello">
              <constructor-arg index="0" value="韩清宗"/>
          </bean>
      
    • 类型匹配

    •  <!--第二种:通过类型匹配,不建议使用-->
          <bean id="hello" class="com.kuang.pojo.Hello">
              <constructor-arg type="java.lang.String" value="韩清宗"/>
          </bean>
      
    • 通过参数名

    •     <!--第三种:直接通过参数名-->
          <bean id="hello" class="com.kuang.pojo.Hello">
              <constructor-arg name="str" value="韩清宗"/>
          </bean>
      
    • 在配置文件加载的时候,容器中的对象已经初始化了

5. Spring配置

5.1 别名

<!--别名,如果添加了别名,我们也可以通过别名获取到这个对象-->
    <alias name="hello" alias="hello"/>

5.2 Bean的配置

<!--
id:bean的唯一的标识符,也就是相当于我们的对象名
class:bean对象所对应的全限定名:包名+类名
name:也是别名,而且name可以同时取多个别名
-->
   <bean id="hello" class="com.kuang.pojo.Hello" name = "user,u2,u3" >
    </bean>

5.3 import

  • 有多个配置文件可以在一个配置文件中引用其他的,直接使用总的就可以了

  • applicationContext.xml

  • <import resource = "beans.xml">
        <import resource = "beans2.xml">
            <import resource = "beans3.xml">
    

6. DI依赖注入环境

6.1 构造器注入

6.2 Set方式注入【重点】

  • 依赖注入:set注入

    • 依赖:bean对象的创建依赖于容器
    • 注入:bean对象的所有属性,都由容器来注入
  • 环境搭建

  • 复杂类型

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

  • public class Student {
        private String name;
        private Address address;
        private String[] books;
        private List<String> hobbys;
        private Map<String,String> card;
        private Set<String> game;
        private String wife;
        private Properties info;
    }
    
  • beans.xml

  • <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="student" class="com.kuang.pojo.Student">
            <!--第二种:普通值注入,value-->
            <property name="name" value="韩清宗"/>
        </bean>
    
    </beans>
    
  • 测试类

  • public class MyTest {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext classPathXmlApplicationContext
                    = new ClassPathXmlApplicationContext("beans.xml");
            Student student = (Student)classPathXmlApplicationContext.getBean("student");
    
            System.out.println(student.getName());
    
        }
    }
    
  • 完善注入信息

  • <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="address" class="com.kuang.pojo.Address">
            <property name="address" value="西安"/>
        </bean>
    
        <bean id="student" class="com.kuang.pojo.Student">
            <!--第二种:普通值注入,value-->
            <property name="name" value="韩清宗"/>
    
            <!--第二种:bean注入,ref-->
            <property name="address" ref="address"/>
    
            <!--数组注入-->
            <property name="books">
                <array>
                    <value>水浒传</value>
                    <value>西游记</value>
                    <value>三国演义</value>
                    <value>红楼梦</value>
                </array>
            </property>
    
            <!--List-->
            <property name="hobbys">
                <list>
                    <value>听歌</value>
                    <value>看电影</value>
                    <value>吃饭</value>
                </list>
            </property>
    
            <!--Map-->
            <property name="card">
                <map>
                    <entry key="身份证" value="111111222222223333"/>
                    <entry key="银行卡" value="12324325326434313243"/>
                </map>
            </property>
    
            <!--set-->
            <property name="game">
                <set>
                    <value>LOL</value>
                    <value>BOB</value>
                    <value>COC</value>
                </set>
            </property>
    
            <!--null-->
            <property name="wife">
                <null></null>
            </property>
    
            <!--properties-->
            <property name="info">
                <props>
                    <prop key="学号">2019</prop>
                    <prop key="性别"></prop>
                    <prop key="姓名">小明</prop>
                </props>
            </property>
    
        </bean>
    
    </beans>
    

6.3 其他方式注入

  • 我们可以使用p命名空间和c命名空间进行注入

  • 官方解释

  • <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:c="http://www.springframework.org/schema/c"
    
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        
        <!--p命名空间注入,可以直接注入属性的值:property-->
       <bean id="user" class="com.kuang.pojo.User" p:name="韩清宗" p:age="18"/>
    
        <!--p命名空间注入,可以构造器注入属性的值:construct-args -->
        <bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="韩清宗"/>
    
    </beans>
    
  • 测试

  •   @Test
        public void test(){
            ClassPathXmlApplicationContext context
                    = new ClassPathXmlApplicationContext("userbeans.xml");
            User user = (User) context.getBean("user2");
            System.out.println(user);
        }
    
  • p命名空间注入,p命名空间注入不能直接使用

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

6.4 bean的作用域

  • ScopeDescription
    singleton(默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。
    prototype将单个 bean 定义的作用域限定为任意数量的对象实例。
    request将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在可感知网络的 Spring ApplicationContext中有效。
    session将单个 bean 定义的范围限定为 HTTP Session的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
    application将单个 bean 定义的范围限定为ServletContext的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
    websocket将单个 bean 定义的范围限定为WebSocket的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
  • 单例模式(spring的默认机制)

  •    <bean id="user" class="com.kuang.pojo.User" p:name="韩清宗" p:age="18" scope="singleton"/>
    
    
  • 原型模式:每次从容器中get都会产生新对象

  •     <bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="韩清宗" scope="prototype"/>
    
    
  • 其余的在web开发中使用

7. bean的自动装配

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

在spring中有三种装配的方式

  • 在xml中显示的配置
  • 在java中显示的配置
  • 隐式的自动装配(掌握)

7.1 测试

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

7.2 ByName自动装配

  • <!--byName:会自动在上下文中查找,和自己对象set方法后面的值对应的beanid-->
        <bean id="people" class="com.kuang.pojo.People" autowire="byName">
            <property name="name" value="韩清宗"/>
        </bean>
    

7.3 ByType自动装配

  •  <!--byName:会自动在上下文中查找,和自己对象类型一样,id可以省略-->
        <bean id="people" class="com.kuang.pojo.People" autowire="byType">
            <property name="name" value="韩清宗"/>
        </bean>
    

7.4 使用注解进行自动装配

  • 使用注解须知

    • 导入约束

    • 配置注解支持( context:annotation-config/ [重要])

    • <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context.xsd">
      
          <context:annotation-config/>
      
      </beans>
      
    • @Autowired

      • 直接在属性上使用即可
      • 还能够在set方法上使用
      • 可以忽略set()方法
    • 科普:

    • @Nullable 字段标记了这个注解,说明这个字段可以为null
      
    • public @interface Autowired{
          boolean required() default true;
      }
      
    • public class People {
      
          //如果显示的定义了Autowired的required的属性为false,说明这个对象可以为null,否则不允许为空
          @Autowired(required = false)
          private Cat cat;
          @ Autowired
          private Dog dog;
          @Autowired
          private String name;
      
    • @Autowired自动装配环境复杂,自动装配无法只通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier="xxx"去配置@Autowired的使用,指定唯一的bean对象注入

    • public class People {
      
          @Autowired
      	@Qualifier(value="cat111")
          private Cat cat;
          @ Autowired
          @Qualifier(value="dog222")
          private Dog dog;
          @Autowired
          private String name;
      
    • @Resource注解

    • @Resource(name = "cat2")
      private Cat cat;
      

    小结:

    • @Resource和@Autowired区别:
      • 都是用来自动装配的,都可以放在属性字段上
      • @Autowired通过byType实现,而且必须要求对象存在
      • @Resource通过默认byname实现,如果找不到名字,则通过bytype实现,都找不到,报错

8. 使用注解开发

8.1 bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

8.2 属性如何注入

//等价于 < bean id="user" class="com.kuang.pojo.User"/>
    //@Component 主键

@Component
public class User {
    //相当于给属性赋值,也可以注入到ser方法上
    @Value("kuang")
    public String name;
}

8.3 衍生的注解

  • @Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
  • dao【@Repository】
  • controller【@Controller】
  • service【@service】
  • 这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean

8.4 自动装配配置

8.5 作用域

  • @Component
    @Scope("singleton")
    public class User {
        //相当于给属性赋值,也可以注入到ser方法上
        @Value("kuang")
        public String name;
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    

8.6 小结

  • xml与注解

    • xml更加万能,适用于任何场合
    • 不是自己的类使用不了,维护相对复杂
  • xml与注解的最佳实现

    • xml用来管理bean;

    • 注解只负责完成属性的注入

    • 需求要开启注解的支持

    • !--指定要扫描的包,这个包下的注解会直接生效-->
          <context:component-scan base-package="com.kuang.pojo"/>
          <context:annotation-config/>
      
      

9. 使用java的方式配置Spring

  • 我们不适用Spring的xml的配置了,全部用java做

  • 实体类

  • //就是把这个类注册到容器中
    @Component
    public class User {
        private String name;
    
        public User(String name) {
            this.name = name;
        }
    
        public User() {
        }
    
        public String getName() {
            return name;
        }
    
        @Value("shenxian")
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
    
  • //配置文件
    package com.kuang.config;
    
    import com.kuang.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    @Configuration
    @Import(kuangConfig2.class)//两个配置文件整合
    public class kuangconfig {
        @Bean
        public User getUser(){
            return new User();
        }
    }
    
    
  • //测试
    import com.kuang.pojo.User;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContextExtensionsKt;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.lang.reflect.AnnotatedElement;
    
    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context
                    = new AnnotationConfigApplicationContext("kuangconfig.class");
            User getUser = (User)context.getBean("getUser");
            System.out.println(getUser.getName());
    
        }
    }
    

10. 代理模式

  • SpringAOP的底层是代理模式

代理模式的分类:

10.1 静态代理

  • 角色分析:
  • 抽象角色:一般会用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实的角色,代理真是角色后,我们一般会做一些附属操作
  • 客户访问代理对象的人

代理模式的好处:

  • 可以使角色的操作更加纯粹,不用关注公众的业务
  • 公众也就交给了代理角色,实现了业务的分工
  • 公众业务发生扩展的时候,方面集中管理
  • 一个动态代理类代理的式一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类

缺点:

  • 一个真实角色就会产生一个代理角色,会使编码的效率变低

  • 代码步骤:

  • 接口

  • //租房的的接口
    public interface Rent {
        public void rent();
    }
    
  • 真实角色

  • //房东
    public class Host implements Rent{
    
        public void rent() {
            System.out.println("房东出租房子");
        }
    }
    
  • 代理角色

  • package com.kuang.demo01;
    
    import com.kuang.Host;
    
    /**
     * Created by admin on 2021/4/19.
     */
    public class Proxy implements Rent {
        private Host host;
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        public Proxy() {
        }
    
        public void rent(){
            host.rent();
        }
    
        public void seeHouse(){
            System.out.println("kanfang");
        }
    
        public void fare(){
            System.out.println("zhongjiefei");
        }
    
        public void heTong(){
            System.out.println("hetong");
        }
    }
    
    
  • 客户端访问代理角色

  • public class Client {
        public static void main(String[] args) {
            Host host = new Host();
            Proxy proxy = new Proxy(host);
            proxy.rent();
        }
    }
    
    

10.2 加深理解

10.3 动态代理

  • 动态代理和静态代理角色一样

  • 动态代理的代理类是动态生成的,不是我们直接写好的

  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

    • 基于接口—JDK动态代理
    • 基于类:cglib
    • java字节码:javasist
  • 需要了解两个类:Proxy 代理,invocationHander 调用处理程序

  • invocationHander

  • import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * Created by admin on 2021/4/20.
     */
    //我们会用这个类自动生成代理类
    public class ProxyInvocationHander implements InvocationHandler{
        //被代理的接口
        private Object rent;
    
        public void setRent(Object rent) {
            this.rent = rent;
        }
    
        public Object getProxy(){
            return Proxy.newProxyInstance
                    (this.getClass().getClassLoader(),
                         rent.getClass().getInterfaces(),
                            this);
        }
    
        //处理代理实例,并返回结果
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //动态代理实例,并返回结果
            Rent result = (Rent)method.invoke(rent, args);
    
    
            return result;
        }
    
  • import com.kuang.Host;
    
    public class Client {
        public static void main(String[] args) {
            //真实角色
            Host host = new Host();
    
            //代理角色
            ProxyInvocationHander pih = new ProxyInvocationHander();
            //通过调用程序处理角色来处理我们调用的接口对象
            pih.setRent(host);
    
            Rent proxy = (Rent) pih.getProxy();
            proxy.rent();
        }
    }
    

11. AOP

11.1 什么是AOP

  • AOP:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,AOP是OOP的延续,使软件开发过程中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一宗衍生范型,利用OOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZXFpS77Y-1618985045028)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1618888721998.png)]

11.2 AOP在Spring中的作用

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

  • 横切关注点:跨越应用程序多个模块的方法或者功能,即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点,如日志,安全,缓存,事务等…

  • 切面(ASPECT):横切关注点被模块化的特殊对象,他是一个类

  • 通知(Advice):切面必须要完成的工作,她是类中的一个方法

  • 目标(Target):被通知对象

  • 代理(Proxy):向目标对应应用通知之后的创建的对象

  • 切入点(PointCut):切面通知执行的"地点"的定义

  • 连接点(JoinPoint):与切入点匹配的执行点

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XoS8P9ya-1618985045029)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1618893391721.png)]

  • 即Aop在不改变原有的代码的情况下,去增加新的功能。

11.3 使用Spring实现Aop

  • 使用AOP织入,需要导入一个依赖包!

  •     <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.4</version>
            </dependency>
        </dependencies>
    

方式一:使用Spring的API接口

  • UserService接口

  • public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void select();
    }
    
  • UserServiceImpl接口实现类

  • package com.kaung.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.kaung.log;
    
    import org.springframework.aop.MethodBeforeAdvice;
    import org.springframework.lang.Nullable;
    
    import java.lang.reflect.Method;
    
    public class Log implements MethodBeforeAdvice{
        //method:要执行的目标代码
        //object:参数
        //o:目标对象
        public void before(Method method, Object[] objects, @Nullable Object o) throws Throwable {
            System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了");
        }
    }
    
    
  • package com.kaung.log;
    
    import org.springframework.aop.AfterAdvice;
    import org.springframework.aop.AfterReturningAdvice;
    import org.springframework.lang.Nullable;
    
    import java.lang.reflect.Method;
    
    public class AfterLog implements AfterReturningAdvice{
        //   returnValue:返回值
        public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
            System.out.println("执行了"+method.getName()+"返回结果为:"+returnValue);
        }
    }
    
  • Aop配置

  • <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!--注册bean-->
        <bean id="userService" class="com.kaung.service.UserServiceImpl"/>
        <bean id="log" class="com.kaung.log.Log"/>
        <bean id="afterLog" class="com.kaung.log.AfterLog"/>
    
        <!--方式一:使用原生的Spring API接口-->
        <!--配置aop:需要导入aop的约束-->
        <aop:config>
            <!--切入点:expression:表达式,execution(要执行的位置!)-->
            <aop:pointcut id="pointcut" expression="execution(* com.kaung.service.UserServiceImpl.*(..))"/>
    
            <!--执行环绕增加-->
            <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
            <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    
        </aop:config>
    
    </beans>
    
  • import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyTest {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            //动态代理代理的是接口
            UserService userService = (UserService)context.getBean("userService");
    
            userService.add();
        }
    }
    

方式二:使用自定义类进行Aop切入(切面定义)

  • <!--方式二:自定义类-->
        <bean id="diy" class="com.kaung.diy.DiyPointCut"/>
    
        <aop:config>
            <!--自定义切面,ref要引用的类-->
            <aop:aspect ref="diy">
                <!--切入点-->
                <aop:pointcut id="point" expression="execution(* com.kaung.diy.DiyPointCut.*(..))"/>
                <!--通知-->
                <aop:before method="before" pointcut-ref="point"/>
                <aop:after method="after" pointcut-ref="point"/>
                
            </aop:aspect>
        </aop:config>
    

方式三:使用注解实现AOP

  •  <!--方式三:利用注解-->
        <bean id="pointCut" class="com.kaung.diy.PointCut"/>
        <!--开启注解支持-->
        <aop:aspectj-autoproxy/>
    

12. 整合Mybatis

步骤

12.1 前期过程

导入相关jar包

  • junit

  • <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    
  • mybatis

  • <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    
  • mysql-connector-java数据库

  • <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    
  • spring相关的

  • <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.10.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.10.RELEASE</version>
    </dependency>
    
  • aop织入

  • <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
  • mybatis-spring【new】

  • <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.2</version>
    </dependency>
    
  • 配置Maven静态资源过滤问题

  • <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>`	
    </build>
    

编写配置文件

  • <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    </project>
    

测试

12.2 回忆mybatis

  • 编写pojo实体类

  • package com.kuang.pojo;
     
    public class User {
        private int id;  //id
        private String name;   //姓名
        private String pwd;   //密码
    }
    
  • 编写mybaits核心配置文件

  • <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
     
        <typeAliases>
            <package name="com.kuang.pojo"/>
        </typeAliases>
     
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
     
        <mappers>
            <package name="com.kuang.dao"/>
        </mappers>
    </configuration>
    
  • 编写UserDao接口

  • public interface UserMapper {
        public List<User> selectUser();
    }
    
  • 编写Mapper.xml

  • <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.kuang.dao.UserMapper">
     
        <select id="selectUser" resultType="User">
          select * from user
        </select>
     
    </mapper>
    
  • 测试

  • @Test
    public void selectUser() throws IOException {
     
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
     
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
     
        List<User> userList = mapper.selectUser();
        for (User user: userList){
            System.out.println(user);
        }
     
        sqlSession.close();
    }
    

编写数据源配置

sqlSessionFactory

sqlSessionTemple

需要给接口加实现类

将自己写的实现类注入到spring中

测试

知识基础

  • 如果使用 Maven 作为构建工具,仅需要在 pom.xml 中加入以下代码即可:

  • <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.2</version>
    </dependency>
    
  • 要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory 和至少一个数据映射器类。

  • 在 MyBatis-Spring 中,可使用SqlSessionFactoryBean来创建 SqlSessionFactory。要配置这个工厂 bean,只需要把下面代码放在 Spring 的 XML 配置文件中:

  • <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource" />
    </bean>
    
  • 使用 SqlSessionFactory 作为构造方法的参数来创建 SqlSessionTemplate 对象。

  • SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession。

  • <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
      <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    
  • 现在,这个 bean 就可以直接注入到你的 DAO bean 中了。你需要在你的 bean 中添加一个 SqlSession 属性,就像下面这样:

    public class UserDaoImpl implements UserDao {
     
      private SqlSession sqlSession;
     
      public void setSqlSession(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
      }
     
      public User getUser(String userId) {
        return sqlSession.getMapper...;
      }
    }
    
  • 按下面这样,注入 SqlSessionTemplate:

    <bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
      <property name="sqlSession" ref="sqlSession" />
    </bean>
    

整合实现一

  • 引入Spring配置文件beans.xml

  • <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
  • 配置数据源替换mybaits的数据源

  • <!--配置数据源:数据源有非常多,可以使用第三方的,也可使使用Spring的-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
  • 配置SqlSessionFactory,关联MyBatis

  • <!--配置SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--关联Mybatis-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/kuang/dao/*.xml"/>
    </bean>
    
  • 注册sqlSessionTemplate,关联sqlSessionFactory;

  • <!--注册sqlSessionTemplate , 关联sqlSessionFactory-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--利用构造器注入-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    
  • 增加Dao接口的实现类;私有化sqlSessionTemplate

  • public class UserDaoImpl implements UserMapper {
     
        //sqlSession不用我们自己创建了,Spring来管理
        private SqlSessionTemplate sqlSession;
     
        public void setSqlSession(SqlSessionTemplate sqlSession) {
            this.sqlSession = sqlSession;
        }
     
        public List<User> selectUser() {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            return mapper.selectUser();
        }
        
    }
    
  • 注册bean实现

  • <bean id="userDao" class="com.kuang.dao.UserDaoImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
    
  • 测试

  •     @Test
        public void test2(){
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            UserMapper mapper = (UserMapper) context.getBean("userDao");
            List<User> user = mapper.selectUser();
            System.out.println(user);
        }
    

实现方式二

  • 将我们上面写的UserDaoImpl修改一下

  • public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {
        public List<User> selectUser() {
            UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
            return mapper.selectUser();
        }
    }
    
  • 修改bean的配置

  • <bean id="userDao" class="com.kuang.dao.UserDaoImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    
  • 测试

  • @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserMapper mapper = (UserMapper) context.getBean("userDao");
        List<User> user = mapper.selectUser();
        System.out.println(user);
    }
    
  • 整合到spring以后可以完全不要mybatis的配置文件,除了这些方式可以实现整合之外,我们还可以使用注解来实现,这个等我们后面学习SpringBoot的时候还会测试整合!

13. 声明式事务

13.1 回顾事务

  • 一组业务要么都成功,要么都失败

事务的ACID原则:

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

导入依赖,建实体类,写接口,导入mybatis配置,整合mybatis(数据源,sqlSessionFactory,sqlSession),写实现类,测试

13.2 spring中的事务管理

  • 声明式事务:AOP
  <property name="sqlSession" ref="sqlSession"/>
```
  • 测试

  •     @Test
        public void test2(){
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            UserMapper mapper = (UserMapper) context.getBean("userDao");
            List<User> user = mapper.selectUser();
            System.out.println(user);
        }
    

实现方式二

  • 将我们上面写的UserDaoImpl修改一下

  • public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {
        public List<User> selectUser() {
            UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
            return mapper.selectUser();
        }
    }
    
  • 修改bean的配置

  • <bean id="userDao" class="com.kuang.dao.UserDaoImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    
  • 测试

  • @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserMapper mapper = (UserMapper) context.getBean("userDao");
        List<User> user = mapper.selectUser();
        System.out.println(user);
    }
    
  • 整合到spring以后可以完全不要mybatis的配置文件,除了这些方式可以实现整合之外,我们还可以使用注解来实现,这个等我们后面学习SpringBoot的时候还会测试整合!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值