Spring5

1、spring

1.1、简介

  • Spring:

    Spring是一个开源框架,它由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson)创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

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

    **轻量——从大小与开销两方面而言Spring都是轻量的。**完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

    控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

    面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

    容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

    框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

    所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

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

  • SSH:struct2+Spring+Hiberbate

  • SSM:SpringMVC+Spring+Mybatis

  • <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.12.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.12.RELEASE</version>
    </dependency>
    
    

1.2、优点

  • Spring是一个开源的免费的框架(容器)

  • Spring是一个轻量级的、非入侵式的框架

  • 控制反转(IOC)、面向切面编程(AOP)

  • 支持事务的处理,对框架整合的支持

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

1.3、组成

在这里插入图片描述
在Spring的官网中有这个介绍:现代化的Java开发!说白就是Spring的开发!
在这里插入图片描述

  • spring Boot
    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速的开发单个微服务
    • 约定大于配置
  • spring Cloud
    • SpringCloud是基于SpringBoot实现的

因为现在大多数公司都在使用SpringBoot进行快速开发,学习springBoot的前提,需要完全掌握Spring以及SpringMVC

2、IOC理论推导

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

我们使用一个Set接口实现

   private UserDao userDao;
   //利用set进行动态实现值的注入!

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

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

之前:
在这里插入图片描述

IOC:
在这里插入图片描述
在这里插入图片描述

3、HelloSpring

<?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
       https://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    <!--使用spring来创建对象,再spring这些都称为bean
    类型 变量名 =new 类型();
    Hello hello=new Hello();

    id=变量名
    class=new 的对象
    property相当于给对象中的属性设置一个值!
    -->
    <bean id="hello" class="com.jx.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>
</beans>
package com.jx.pojo;

public class Hello {
    private String str;
    public Hello() {
    }
    public Hello(String str) {
        this.str = str;
    }

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

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

在这里插入图片描述

4、IOC创建对象的方式

  1. 使用无参构造创造对象,默认

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

    1. 下标赋值

        <!--第一种,下标赋值-->
          <bean id="user" class="com.jx.pojo.User">
              <constructor-arg index="0" value="兔兔"/>
          </bean>
      
    2. 类型

      <!--第二种方式,通过类型创建,不建议使用!-->
      <bean id="user" class="com.jx.pojo.User">   <constructor-arg type="java.lang.String" value="兔兔"/>
      </bean>
      
    3. 参数名

      <!--第三种,直接通过参数名设置-->
          <bean id="user" class="com.jx.pojo.User">
              <constructor-arg name="name" value="兔兔"/>
          </bean>  
      

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

5、spring配置

5.1、别名

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

5.2、Bean的配置

<!--
     id:bean的唯一标识符,也就是相当于我们学的对象名
     class:bean对象所对应的全限定名:包名+类型
     name:也是别名,而且可同时取多个别名
     -->
<bean id="user" class="com.jx.pojo.User" name="user2">
    <property name="name" value="兔兔"/>
</bean>

5.3、import

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

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

  • 张三

  • 李四

  • 王五

  • applicationContext.xml

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

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

6、依赖注入

6.1、构造器注入

前面已经说过了

6.2、Set方式注入(重点)

  • 依赖注入:Set注入!

    • 依赖:bean对象的创建依赖于容器

    • 注入:bean对象中 所有属性,由容器来注入!

【环境搭建】

  1. 复杂类型

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

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

 ```java
 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<String> getHobbys() {
     return hobbys;
 }
 
 public void setHobbys(List<String> hobbys) {
     this.hobbys = hobbys;
 }
 
 public Map<String, String> getCard() {
     return card;
 }
 
 public void setCard(Map<String, String> card) {
     this.card = card;
 }
 
 public Set<String> getGames() {
     return games;
 }
 
 public void setGames(Set<String> 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 String toString() {
     return "Student{" +
             "name='" + name + '\'' +
             ", address=" + address +
             ", books=" + Arrays.toString(books) +
             ", hobbys=" + hobbys +
             ", card=" + card +
             ", games=" + games +
             ", wife='" + wife + '\'' +
             ", info=" + info +
             '}';
 }

}

3.beans.xml

<bean id="student" class="com.jx.pojo.Student">
    <!--普通值注入-->
    <property name="name" value="兔兔"/>
</bean>

4.测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
    }
}

完善注入信息

<bean id="address" class="com.jx.pojo.Address">
        <property name="address" value="山东"/>
  </bean>   
<bean id="student" class="com.jx.pojo.Student">
    <!--普通值注入-->
    <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="12345678945133"/>
            <entry key="银行卡" value="26645678945133"/>
        </map>
    </property>
    <!--第五种,Set-->
    <property name="games">
        <set>
            <value>LOL</value>
            <value>COC</value>
        </set>
    </property>
    <!--第六种,null-->
    <property name="wife">
        <null/>
    </property>
    <!--第七种,properties-->
    <property name="info">
        <props>
            <prop key="学号">2017521648751</prop>
            <prop key="姓名"></prop>
        </props>
    </property>

</bean>

6.3、扩展方式注入

  1. p命名空间注入

    <!--p命名空间注入,可以直接注入属性的值:property-->
    <bean id="user" class="com.jx.pojo.User" p:name="兔兔" p:age="18"/>
    
  2. c命名空间注入

<!--c命名空间注入,有参,通过构造器注入:constructs-args-->
<bean id="user2" class="com.jx.pojo.User" c:age="18" c:name="兔兔"/>

测试:

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
        /*
        * Student{
        * name='兔兔',
        * address=Address{address='山东'},
        * books=[红楼梦, 西游记, 水浒传, 三国演义],
        * hobbys=[听歌, 看电影, 追剧],
        * card={身份证=12345678945133,
        * 银行卡=26645678945133},
        * games=[LOL, COC],
        * wife='null',
        * info={学号=2017521648751, 姓名=女}}
        * */
    }
    @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = (User) context.getBean("user2");
        System.out.println(user);

    }

6.4、Bean的作用域(scope)

作用域描述
singleton在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。
prototype每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。
request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。
session同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。
application限定一个Bean的作用域为ServletContext的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。
  1. 单例模式(Spring默认机制)
  2. 原型模式:每次从容器中get时,都会产生一个新对象
  3. 其余request、session、application只能在web开发中使用

7、Bean的自动装配

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

在Spring中有三种装配的方式

  1. 在xml中显示的装配
  2. 在Java中显示装配
  3. 隐式的自动装配bean(重要)

7.1、测试

  1. 环境搭建

    • 一个人有两个宠物
public class People {
    private Cat cat;
    private Dog dog;
    private String 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;
    }

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}
public class Cat {
    public void shout(){
        System.out.println("喵喵喵");
    }
}
public class Dog {
    public void shout(){
        System.out.println("汪汪汪");
    }
}
<bean id="cat" class="com.jx.pojo.Cat"/>
    <bean id="dog" class="com.jx.pojo.Dog"/>
    <bean id="people" class="com.jx.pojo.People">
        <property name="name" value="兔兔"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>

7.2、ByName自动装配

<bean id="people" class="com.jx.pojo.People" autowire="byName">
    <property name="name" value="兔兔"/>
</bean>

7.3、ByType自动装配

<bean class="com.jx.pojo.Cat"/>
<bean class="com.jx.pojo.Dog"/>
<!--
    ByName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid
    ByName:会自动在容器上下文中查找,和自己对象对象属性类型相同的bean,可以不用id

    -->
<bean id="people" class="com.jx.pojo.People" autowire="byType">
    <property name="name" value="兔兔"/>
</bean>

小结:

  1. ByName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法值一致
  2. ByTame的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致

7.4、使用注解实现自动装配

jdk1.5支持的注解,Spring从2.5就支持注解了!

要使用注解须知:

导入约束 context约束

配置注解的支持: contex: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:contex="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           https://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <contex:annotation-config/>
</beans>

@Autowaired

  1. 直接在属性上使用即可!也可以在set方式上使用
  2. 使用Autowaired我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在且符合名字byname

科普:

@NUllable 字段标记了这个注解,说明这个字段可以为null

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

如果@Autowaired自动装配的环境比较复杂,自动装配无法通过一个注解完成@Autowaired的时候,我们可以使用**@Qualifier(value=“xxx”)**去配置@Autowaired的使用,指定一个唯一的bean对象注入

 @Autowired
    @Qualifier(value = "cat111")
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog222")
    private Dog dog;
    private String name;
}

@Resource

 @Resource(name = "cat2")
    private Cat cat;
   @Resource
    private Dog dog;
    private String name;

小结:

@Resource与 @Autowired的区别:

  1. 都是用来自动装配的,都可以放在属性字段上
  2. @Autowired默认通过bytype类型查找,找不到就通过byname找
  3. 而@Resource默认按byName自动注入,找不到就通过byType 实现!

8、使用注解开发

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

使用注解需要导入context,增加注解支持!

<?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:contex="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启注解支持-->

    <contex:annotation-config/>

</beans>

8.1、注解说明

  • @Autowired默认通过bytype类型查找,找不到就通过byname找,如果@Autowaired自动装配的环境比较复杂,自动装配无法通过一个注解完成@Autowaired的时候,我们可以使用**@Qualifier(value=“xxx”)**去配置
  • 而@Resource默认按byName自动注入,找不到就通过byType 实现!
  • @NUllable 字段标记了这个注解,说明这个字段可以为null
  • @Component 组件,放在类上,说明这个类被spring管理了
  1. bean

  2. 属性如何注入

    //等价与 <bean id="user" class="com.jx.pojo.User"/>
    @Component //组件
    public class User {
        //相当于<property name="name" value="兔兔"/>
        @Value("兔兔")
        public String name;
    }
    
  3. 衍生的注解

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

    • dao【@Repository】

    • service【@Service】

    • controller【@Controller】

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

  4. 自动装配

    @Autowired默认通过bytype类型查找,找不到就通过byname找,如果@Autowaired自动装配的环境比较复杂,自动装配无法通过一个注解完成@Autowaired的时候,我们可以使用**@Qualifier(value="xxx")**去配置
    而@Resource默认按byName自动注入,找不到就通过byType 实现!
    @NUllable 字段标记了这个注解,说明这个字段可以为null
    
  5. 作用域

    //等价与 <bean id="user" class="com.jx.pojo.User"/>
    @Component //组件
    @Scope("prototype")
    public class User {
        //相当于<property name="name" value="兔兔"/>
        @Value("兔兔")
        public String name;
    }
    
  6. 小结

    xml与注解:

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

    xml与注解最佳实践:

    • xml用来管理bean

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

    • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,开启注解支持:

      <!--指定扫描的包,这个包下的注解就会生效-->
      <contex:component-scan base-package="com.jx"/>
      <!--开启注解支持-->
      <contex:annotation-config/>
      

9、使用Java的方式配置Spring

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

javaConfig

实体类:

//这里这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }
    @Value("兔兔")//注入值
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
配置类:
@Configuration//这个也会被Spring容器中托管,注册到容器中,因为他本来就是一个@Component
//@Configuration代表这是一个配置类,就和我们之前看到的beans.xml一样
public class MyConfig {
    //注册一个bean,就相当于我们之前写的一个bean标签
    //这个方法的名字,就相当于bean标签中的id属性
    //这个方法的返回值,就相当于备案标签中的class属性
    @Bean
    public User getUser(){
        return new User();//就是返回要注入到bean的对象
    }
}
测试类:
public class MyTest {
    public static void main(String[] args) {
        //如果完全使用了配置类方式去做,我们就只能通过AnnotationConfigApplicationContext上下文来获取容器,通过配置类的class对象加载!
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User getUser = (User) context.getBean("getUser");
        System.out.println(getUser.getName());

    }
}

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

10、代理模式

为什么要学习代理模式?

因为这是SpringAOP的底层【SpringAOP 和 SpringMVC】

代理模式的分类:

  • 静态代理
  • 动态代理

10.1、静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决

  • 真实角色:被代理的角色

  • 代理角色:代理真实角色,代理真是角色后,饿哦们一般会做一些附属操作

  • 客户:访问代理对象的人

代码步骤:

  1. 接口

    public interface Rent {
        public void rent();
    }
    
  2. 真实角色

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

    public class Proxy {
        private Host host;
    
        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
        public void rent(){
            seeHouse();
            host.rent();
            hetong();
            fare();
    
        }
        //看房
        public void seeHouse(){
            System.out.println("中介带你看房");
        }
        public void hetong(){
            System.out.println("签租赁合同");
        }
        //收中介费
        public void  fare(){
            System.out.println("收中介费");
        }
    }
    
  4. 客户端访问代理角色

    public class Client {
        public static void main(String[] args) {
            //房东租房
            Host host = new Host();
            //代理,中介帮房东租房子
            Proxy proxy = new Proxy(host);
            proxy.rent();
        }
    }
    

代理模式的好处:

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

缺点:

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

10.2、加深理解

  1. 接口

    public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void query();
    
    }
    
  2. 真实角色

    //真实对象
    public class UserServiceImpl implements UserService {
        public void add() {
            System.out.println("使用了add方法");
            System.out.println("增加");
        }
    
        public void delete() {
            System.out.println("删除");
        }
    
        public void update() {
            System.out.println("更新");
        }
    
        public void query() {
            System.out.println("查询");
        }
    }
    
  3. 代理角色

    public class UserServiceProxy implements UserService{
        private UserServiceImpl userService;
    
        public void setUserService(UserServiceImpl userService) {
            this.userService = userService;
        }
    
        public void add() {
            log("add");
            userService.add();
        }
    
        public void delete() {
            log("delete");
            userService.delete();
        }
    
        public void update() {
            log("update");
            userService.update();
        }
    
        public void query() {
            log("query");
            userService.query();
        }
        public void log(String msg){
            System.out.println("使用了"+msg+"方法");
        }
    
    
    }
    
  4. 客户端访问代理角色

    public class Client {
        public static void main(String[] args) {
            UserServiceImpl userService = new UserServiceImpl();
            UserServiceProxy userServiceProxy = new UserServiceProxy();
            userServiceProxy.setUserService(userService);
            userServiceProxy.add();
        }
    }
    

10.3、动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口—JDK动态代理
    • 基于类:cglib
    • java字节码实现:javasist

需要了解两个类:Proxy 代理,InvocationHandler:调用处理程序

动态代理的好处:

  1. 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务

  2. 公共业务就交给了代理角色,实现了业务的分工

  3. 公共业务发生扩展,方便集中管理

  4. 一个动态代理类代理的是一个接口,一般就是对应的一类业务

  5. 一个动态代理类可以代理多个类,只要实现了对应的接口即

//这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

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


    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理的本质,就是使用反射机制实现!
        Object result = method.invoke(target, args);
        return result;
    }
    public void log(String msg){
        System.out.println("执行了"+msg+"方法");
    }


}
public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService=new UserServiceImpl();
        //代理角色
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userService);//设置要代理的对象
        //动态生成代理类
        UserService proxy = (UserService) pih.getProxy();
        proxy.add();

    }
}

11、AOP

11.1、什么是AOP

在这里插入图片描述
在这里插入图片描述

11.2、AOP在Spring中的作用

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

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

  • 切面:横切关注点 被模块化的特殊对象。即,它是一个类。

  • 通知:切面必须要完成的工作。即,它是类中的一个方法

  • 目标:被通知对象

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

  • 切入点:切面通知 执行的“地点”的定义

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

在这里插入图片描述
在这里插入图片描述

11.3、使用Spring实现Aop

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

//method:要执行的目标对象的方法
//objects:参数
//o:目标对象
public void before(Method method, Object[] objects, Object o) throws Throwable {
    System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了");
}
public class AfterLog implements AfterReturningAdvice {
    //returnValue返回值
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"返回结果为"+returnValue);
    }
}
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.add();
    }

}
<!--配置aop:需要导入aop的约束-->
<aop:config>
    <!--切入点 execution(要执行的位置)-->
    <aop:pointcut id="pointcut" expression="execution(* com.jx.service.UserServiceImpl.*(..))"/>
    <!--执行环境增加-->
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>

</aop:config>

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

public class DiyPointCut {
    public void before(){
        System.out.println("方法执行前");
    }
    public void after(){
        System.out.println("方法执行后");
    }
}
<!--方式二自定义类 -->
<bean id="diy" class="com.jx.diy.DiyPointCut"/>
<aop:config>
    <!--自定义切面,ref 要引用的类-->
    <aop:aspect ref="diy">
        <!--切入点-->
        <aop:pointcut id="point" expression="execution(* com.jx.service.UserServiceImpl.*(..))"/>
        <!--通知-->
        <aop:before method="before" pointcut-ref="point"/>
        <aop:after method="after" pointcut-ref="point"/>
    </aop:aspect>
</aop:config>

方式三:使用注解实现

@Aspect//标注这个类是一个切面
public class AnnotationPoinCut {
    @Before("execution(* com.jx.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }
    @After("execution(* com.jx.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }
}
<!--方式三-->
<bean id="annotationPoinCut" class="com.jx.diy.AnnotationPoinCut"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>

12、整合Mybatis

步骤:

  1. 导入相关jar包
    • junit
    • mybatis
    • mysql数据库
    • spring相关的
    • aop织入
    • mybatis-spring【new】
  2. 编写配置文件
  3. 测试

12.1、回忆mybatis

  1. 编写实体类
  2. 编写核心配置文件
  3. 编写接口
  4. 编写Mapper.xml
  5. 测试

12.2、mybatis-spring

  1. 编写数据源配置

  2. sqlSessionFactory

    <?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
           https://www.springframework.org/schema/beans/spring-beans-3.2.xsd
           http://www.springframework.org/schema/aop
           https://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--DataSource:使用Spring的数据源替换Mybatis的配置  c3p0 dbcp druid
        我们这里使用Spring提供的JDBC-->
        <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/ssmbuild?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </bean>
        <!--sqlSessionFactory-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="datasource"/>
            <!--绑定Mybatis配置文件-->
            <property name="configLocation" value="mybatis-config.xml"/>
            <property name="mapperLocations" value="classpath:com/jx/mapper/*.xml"/>
        </bean>
        <!--SqlSessionTemplate:就是我们使用的sqlSession-->
        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
            <!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
            <constructor-arg index="0" ref="sqlSessionFactory"/>
        </bean>
        <bean id="bookMapper" class="com.jx.mapper.BookMapperImpl">
            <property name="sqlSession" ref="sqlSession"/>
        </bean>
    </beans>
    
  3. sqlSessionTemplate

    public class BookMapperImpl implements BookMapper{
        //我们的所有操作,在原来都使用sqlSession来执行,现在都使用SqlSessionTemplate;
        private SqlSessionTemplate sqlSession;
    
        public void setSqlSession(SqlSessionTemplate sqlSession) {
            this.sqlSession = sqlSession;
        }
    
        public List<Book> selectBook() {
            BookMapper mapper = sqlSession.getMapper(BookMapper.class);
            return mapper.selectBook();
    
        }
    }
    
  4. 需要给接口加实现类

public class BookMapperImpl2 extends SqlSessionDaoSupport implements  BookMapper {
    public List<Book> selectBook() {
        SqlSession sqlSession = getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        return getSqlSession().getMapper(BookMapper.class).selectBook();
    }
}
  1. 将自己写的实现类注入到spring中

    <bean id="bookMapper2" class="com.jx.mapper.BookMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
    
  2. 测试使用即可

    public class MyTest {
        @Test
        public void test() throws IOException {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
            BookMapper bookMapper = (BookMapper) context.getBean("bookMapper");
            for (Book book : bookMapper.selectBook()) {
                System.out.println(book);
            }
        }
    }
    

13、声明式事务

13.1 回顾事务

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

事务ACID原则:

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

13.2、spring中的事务管理

  • 声明式事务:AOP

    <!--配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="datasource"/>
    </bean>
    <!--结合AOP实现事务的植入-->
    <!--配置事务的类-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--给哪些方法配置事务-->
        <!--配置事务的传播特性-->
        <tx:attributes>
            <tx:method name="add"/>
            <tx:method name="delete"/>
            <tx:method name="update"/>
            <tx:method name="query"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    <!--配置事务切入-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.jx.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
    
  • 编辑式事务:需要在代码中,进行事务管理

思考:

为什么需要事务?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值