| ## 1.1、Spring 简介 |
|
| - Spring:春天------->给软件行业带来了春天! |
| - 2002,首次推出了Spring框架的雏形;interface21框架! |
| - Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。 |
| - Rod Johnson,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他说悉尼大学的博士,然而他的专业不是计算机,而是音乐学。 |
| - spring理念:使现有点技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架! |
| - SSH:Struct2 + Spring + Hibernate! |
| - SSM: SpringMvc + Spring + Mybatis! |
|
|
|
| 官网:https://spring.io/projects/spring-framework |
|
| 官网下载地址:http://repo.spring.io/release/org/springframework/spring |
|
| GitHub:https://github.com/spring-projects/spring-framework |
|
| ```xml |
|
| org.springframework |
| spring-webmvc |
| 5.3.10 |
|
|
|
| org.springframework |
| spring-jdbc |
| 5.3.10 |
|
| ``` |
|
| ## 1.2、 优点 |
|
| - Spring是一个开源的免费的框架(容器)! |
| - Spring是一个轻量级的、非入侵式的框架! |
| - 控制反转(IOC),面向切面编程(AOP)! |
| - 支持事务的处理,对框架整合的支持! |
|
| 总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架! |
|
| ## 1.3、 组成 |
|
![img]() |
|
| ## 1.4、 拓展 |
|
![image-20211023201948628]() |
|
| - Spring Boot |
| - 一个快速开发的脚手架。 |
| - 基于SpringBoot可以快速的开发单个微服务。 |
| - 约定大于配置! |
| - Spring Cloud |
| - SpringCloud 是基于SpringBoot实现的 |
|
| 现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring和SpringMVC!承上启下的作用! |
|
| 弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称配置地域! |
|
| # 2、 IOC理论推导 |
|
| 1. UserDao 接口 |
| 2. UserDaoImpl 实现类 |
| 3. UserService 业务接口 |
| 4. UserServiecImpl 业务实现类 |
|
| 在之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,修改一次的成本代价十分昂贵! |
|
| 我们使用了一个Set接口实现,已经发生了革命性的变化! |
|
| ```java |
| private UserDao userDao; |
|
| //利用set进行动态实现值的注入! |
| public void setUserDao(UserDao userDao) { |
| this.userDao = userDao; |
| } |
| ``` |
|
| - 之前,程序是主动创建对象!控制权在程序猿手上! |
| - 使用了set注入后,程序不再具有主动性,而是变成了被动的接受对象! |
|
| 这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了,系统的耦合性打打降低,可以更加专注的在业务都实现上!这是IOC的原型! |
|
| IOC本质 |
|
| 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。 |
|
| 采用XML方式配置Bean的时候,Bean的定义信息涩和现实分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接可以注解的形式定义在实现类中,从而达到了零配置的目的。 |
|
| 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的事IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。 |
|
|
|
| # 3、 Hello Spring |
|
| bean配置 |
|
| ```xml |
|
| <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"> |
|
|
|
|
| ``` |
|
| 编写POJO |
|
| ```java |
| package com.xia.pojo; |
|
| public class User { |
| private String name; |
|
| public String getName() { |
| return name; |
| } |
|
| public void setName(String name) { |
| this.name = name; |
| } |
|
| public void show() { |
| System.out.println("name:" + name); |
| } |
|
| @Override |
| public String toString() { |
| return "User{" + |
| "name='" + name + ''' + |
| '}'; |
| } |
| } |
| ``` |
|
| 测试 |
|
| ```java |
| package com.xia; |
|
| import com.xia.pojo.User; |
| import org.springframework.context.ApplicationContext; |
| import org.springframework.context.support.ClassPathXmlApplicationContext; |
| import org.testng.annotations.Test; |
|
| public class MyTest { |
| @Test |
| public void mySpringTest(){ |
| ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); |
| User user = (User) context.getBean("user"); |
| user.setName("王小姐"); |
| user.show(); |
| } |
| } |
| ``` |
|
| 思考问题 |
|
| - User对象是谁创建的? |
|
| User对象说由Spring创建的 |
|
| - User对象的属性是怎么设置的? |
|
| User对象的属性是由Spring容器设置的 |
|
| 这个过程就叫控制反转: |
|
| 控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象由Spring来创建 |
|
| 反转:程序本身不创建对象,而变成被动的接收对象。 |
|
| 依赖注入:就是利用set方法来进行注入。 |
|
| IoC是一种编程思想,由主动点编程编程被动的接收。 |
|
| 可以通过new ClassPathApplicationContext去浏览底层源码。 |
|
| OK,到了现在,我们彻底不用在程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IoC就是一句话:对象由Spring来创建,管理,装配! |
|
| # 4、 IoC创建对象的方式 |
|
| 1. 使用无参构造创建对象,默认! |
|
| 2. 假设我们要使用有参构造创建对象。 |
|
| 1. 下标赋值 |
|
| ```xml |
|
|
|
| ``` |
|
| 2. 类型 |
|
| ```xml |
|
|
|
|
| ``` |
|
| 3. 参数名 |
|
| ```xml |
|
|
|
|
| ``` |
|
| 总结:在配置文件加载的时候,容器中管理的对象就已经初始化了! |
|
| # 5、 Spring配置 |
|
| ## 5.1、 别名 |
|
| ```xml |
|
|
| ``` |
|
| ## 5.2、 Bean的配置 |
|
| ```xml |
| <!-- |
|
|
|
|
|
| ``` |
|
| ## 5.3、 import |
|
| 这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个 |
|
| 假设,现在项目中有多个人开发,这三个人负责不同的类的开发,不同的类需要注册在不同的bean中,文名可以利用import将所有人的beans.xml合并为一个总的! |
|
| - 张三 |
|
| - 李四 |
|
| - 王五 |
|
| - applicationContext.xml |
|
| ```xml |
|
| ``` |
|
| # 6、 依赖注入 |
|
| ## 6.1、 构造器注入 |
|
| 前面已经说过了 |
|
| ## 6.2、 Set方法注入 【重点】 |
|
| - 依赖注入:Set注入! |
| - 依赖:bean对象的创建依赖于容器 |
| - 注入:bean对象中的所有属性,由容器来注入! |
|
| 【环境搭建】 |
|
| 1. 复杂类型 |
|
| ```java |
| package com.xia.pojo; |
|
| public class Address { |
| private String address; |
|
| public String getAddress() { |
| return address; |
| } |
| public Address(){} |
|
| public Address(String address) { |
| this.address = address; |
| } |
|
| public void setAddress(String address) { |
| this.address = address; |
| } |
|
| @Override |
| public String toString() { |
| return "Address{" + |
| "address='" + address + ''' + |
| '}'; |
| } |
| } |
| ``` |
|
| 2. 真实测试对象 |
|
| ```java |
| package com.xia.pojo; |
|
| import java.util.*; |
|
| public class Student { |
| private Address address; |
| private String[] book; |
| private String name; |
| private List hobbys; |
| private Map<String,Object> card; |
| private Set games; |
| private String wife; |
| private Properties info; |
|
| public Address getAddress() { |
| return address; |
| } |
|
| public void setAddress(Address address) { |
| this.address = address; |
| } |
|
| public String[] getBook() { |
| return book; |
| } |
|
| public void setBook(String[] book) { |
| this.book = book; |
| } |
|
| public String getName() { |
| return name; |
| } |
|
| public void setName(String name) { |
| this.name = name; |
| } |
|
| public List getHobbys() { |
| return hobbys; |
| } |
|
| public void setHobbys(List hobbys) { |
| this.hobbys = hobbys; |
| } |
|
| public Map<String, Object> getCard() { |
| return card; |
| } |
|
| public void setCard(Map<String, Object> card) { |
| this.card = card; |
| } |
|
| public String getWife() { |
| return wife; |
| } |
|
| public void setWife(String wife) { |
| this.wife = wife; |
| } |
|
| public Set getGames() { |
| return games; |
| } |
|
| public void setGames(Set games) { |
| this.games = games; |
| } |
|
| public Properties getInfo() { |
| return info; |
| } |
|
| public void setInfo(Properties info) { |
| this.info = info; |
| } |
|
| @Override |
| public String toString() { |
| return "Student{" + |
| "address=" + address + |
| ", book=" + Arrays.toString(book) + |
| ", name='" + name + ''' + |
| ", hobbys=" + hobbys + |
| ", card=" + card + |
| ", games=" + games + |
| ", wife='" + wife + ''' + |
| ", info=" + info + |
| '}'; |
| } |
| } |
| ``` |
|
| 3. applicationContext.xml |
|
| ```xml |
|
| <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"> |
|
|
|
|
|
|
|
| ``` |
|
| 4. 测试类 |
|
| ```java |
| public class MyTest { |
| @Test |
| public void myTest(){ |
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); |
| Student student = (Student) context.getBean("student"); |
| System.out.println(student.getName()); |
| } |
| } |
| ``` |
|
|
| 完善注入信息 |
|
| ```xml |
|
| <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"> |
|
|
|
|
|
|
|
|
|
| 三国演义 |
| 红楼梦 |
| 水浒传 |
| 西游记 |
|
|
|
|
|
|
|
|
|
|
|
|
| LOL |
| PSF |
| FC |
|
|
|
|
|
| 动漫 |
| 游戏 |
| 听歌 |
|
|
|
|
|
|
|
|
|
| com.mysql.jdbc.Driver |
| localhost:3306/mybatis |
| root |
| 123456 |
|
|
|
|
|
|
|
|
| ``` |
|
|
|
| ## 6.3、 拓展方式注入 |
|
| 我们可以使用P命名空间和C命名空间进行注入 |
|
| 官方解释: |
|
| 使用: |
|
| ```xml |
|
| <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"> |
|
|
|
|
|
|
|
|
| ``` |
|
| 测试: |
|
| ```java |
| @Test |
| public void myTestUser(){ |
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); |
| User user = context.getBean("user", User.class); |
| System.out.println(user.toString()); |
| } |
| ``` |
|
| 注意:p命名和c命名空间不能直接使用,需要导入xml约束! |
|
| ```xml |
| xmlns:p="http://www.springframework.org/schema/p" |
| xmlns:c="http://www.springframework.org/schema/c" |
| ``` |
|
| ## 6.4、 bean的作用域 |
|
|
|
|
|
|
|
|
|
|
| 1. 单例模式(Spring默认机制) |
|
| ```xml |
|
| ``` |
|
| 2. 原型模式:每一次从容器中get的时候,都会产生一个新的对象 |
|
| ```xml |
|
| ``` |
|
| 3. 其余的request、session、application,这些只能在web开发中使用到! |
|
| # 7、 Bean的自动装配 |
|
| - 自动装配是Spring满足bean依赖的一种方式! |
| - Spring会在上下文中自动寻找,并自动给bean装配属性@ |
|
| 在Spring中有三种自动装配的方式 |
|
| 1. 在xml中显示的配置 |
| 2. 在java中显示配置 |
| 3. 隐式的自动装配bean 【重要】 |
|
| ## 7.1、 测试 |
|
| 环境搭建:一个人有两个宠物! |
|
| ## 7.2、 ByName自动装配 |
|
| ```xml |
|
| <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"> |
|
|
|
|
|
|
| ``` |
|
| ## 7.3、 ByType自动装配 |
|
| ```xml |
|
| <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"> |
|
|
|
|
|
|
| ``` |
|
| 小结: |
|
| - byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致! |
| - byTpye的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致! |
|
| ## 7.4、 使用注解实现自动装配 |
|
| jdk1.5支持的注解,Spring2.5就支持注解了! |
|
| The introduction of annotation-based configuration raised the question of whether this approach is "better" thanXML. |
|
| 要使用注解须知: |
|
| 1. 导入约束 |
|
| 2. 配置注解的支持: |
|
| ```xml |
|
| <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/ |
|
|
| ``` |
|
|
|
| @Autowired |
|
| 直接在属性上使用即可!也可以在set方法上使用! |
|
| 使用Autowired 我们可以不用编写set方法,前提是你这个自动装配的属性在IoC容器中存在,且符合byType! |
|
| 科普: |
|
| ```xml |
| @Nullable 字段标记了这个注解,说明这个字段可以为null; |
| ``` |
|
| ```java |
| public @interface Autowired { |
| boolean required() default true; |
| } |
| ``` |
|
| 测试代码 |
|
| ```xml |
|
| <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" |
| 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/context |
| http://www.springframework.org/schema/context/spring-context.xsd |
| http://www.springframework.org/schema/aop |
| http://www.springframework.org/schema/context/spring-aop.xsd"> |
|
| context:annotation-config/ |
|
|
|
|
|
| ``` |
|
| ```java |
| public class People { |
| //如果现实定义了Autowired的required属性为false,说明这个对象可以为null |
| @Autowired(required = false) |
| private Dog dog; |
| @Autowired |
| //如果有多个对象,可以通过Qualifier指定对象 |
| @Qualifier(value = "cat2") |
| private Cat cat; |
|
| public Dog getDog() { |
| return dog; |
| } |
|
| public void setDog(Dog dog) { |
| this.dog = dog; |
| } |
|
| public Cat getCat() { |
| return cat; |
| } |
|
| public void setCat(Cat cat) { |
| this.cat = cat; |
| } |
| } |
| ``` |
|
| 如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value = "xxx")去配置@Autowired的使用,指定一个唯一的bean对象注入! |
|
| ```java |
| public class People { |
|
| @Autowired |
| @Qualifier(value = "dog2") |
| private Dog dog; |
|
| @Autowired |
| @Qualifier(value = "cat2") |
| private Cat cat; |
| } |
| ``` |
|
| @Resource注解 |
|
| ```java |
| import javax.annotation.Resource; |
|
| public class People { |
| @Resource |
| private Dog dog; |
| @Resource(name = "cat2") |
| private Cat cat; |
|
| public Dog getDog() { |
| return dog; |
| } |
|
| public void setDog(Dog dog) { |
| this.dog = dog; |
| } |
|
| public Cat getCat() { |
| return cat; |
| } |
|
| public void setCat(Cat cat) { |
| this.cat = cat; |
| } |
| } |
| ``` |
|
| 小结: |
|
| @Autowired 和@Resource 的区别: |
|
| - 都是用来自动装配的,都可以放在属性字段上 |
| - @Autowired 先通过byType的方式实现,找不到再通过byName实现 |
| - @Resource 先通过byName的方式实现,找不到再通过byType实现,如果都找不到的情况下,就会报错【常用】 |
| - 执行顺序不同:@Autowired先通过byType,@Resource先通过byName |
|
|
|
| # 8、 使用注解开发 |
|
| 在Spring4之后,要使用注解开发,必须要保证aop的包导入了 |
|
| 使用注解需要导入context约束,增加注解的支持 |
|
| 1. bean |
|
| 2. 属性如何注入 |
|
| ```java |
| import org.springframework.beans.factory.annotation.Value; |
| import org.springframework.stereotype.Component; |
|
| //相当于 |
| @Component |
| public class User { |
|
| //相当于 |
| @Value("蜗牛小姐") |
| public String name; |
|
| public void setName(String name) { |
| } |
| } |
| ``` |
|
| 3. 衍生的注解 |
|
| @Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层! |
|
| - dao 【@Repository】 |
|
| - service 【@Service】 |
|
| - controller 【@Controller】 |
|
| 这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean |
|
| 4. 自动装配 |
|
| ```xml |
| - @Autowired |
| 自动装配通过类型,名字。 |
| 如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx") |
| - @Nullable |
| 字段标记了这个注解,说明这个字段可以为null; |
| - @Resource |
| 自动装配通过名字,类型。 |
| ``` |
|
| 5. 作用域 |
|
| ```java |
| @Component |
| @Scope("prototype") |
| public class User { |
| @Value("蜗牛小姐") |
| public String name; |
|
| public void setName(String name) { |
| } |
| } |
| ``` |
|
| 6. 小结 |
|
| xml与注解: |
|
| - xml更加万能,适用于任何场合!维护简单方便 |
| - 注解不是自己类使用不了,维护相对复杂! |
|
| xml与注解最佳实践: |
|
| - xml用来管理bean。 |
|
| - 注解只负责完成属性的注入 |
|
| - 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持 |
|
| ```xml |
|
| <context:component-scan base-package="com.xia"/> |
| context:annotation-config/ |
| ``` |
|
|
| # 9、 使用Java的方式配置Spring |
|
| 我们现在要完全不使用Spring的xml配置,全权交给Java来做! |
|
| JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能! |
|
| 实体类 |
|
| ```java |
| import org.springframework.beans.factory.annotation.Value; |
| import org.springframework.stereotype.Component; |
|
| @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 + ''' + |
| '}'; |
| } |
| } |
| ``` |
|
| 配置文件 |
|
| ```java |
| import com.xia.pojo.User; |
| import org.springframework.context.annotation.Bean; |
| import org.springframework.context.annotation.ComponentScan; |
| import org.springframework.context.annotation.Configuration; |
| import org.springframework.context.annotation.Import; |
|
| //这个也会被Spring容器托管,注册到容器中,因为他本来就是一个@Component |
| //@Configuration代表这是一个配置类,就和beans.xml一样 |
| @Configuration |
| @ComponentScan("com.xia.pojo") |
| @Import(WangConfig.class) |
| public class XiaConfig { |
|
| /*注册一个bean,就相当于我们写一个bean标签 |
| 这个方法的名字,就相当于bean标签中的id属性 |
| 这个方法的返回值,就相当于bean标签中的class属性*/ |
| @Bean |
| public User getUser() { |
| return new User(); //就是返回要注入到bean的对象 |
| } |
| } |
| ``` |
|
| 测试类! |
|
| ```java |
| import org.springframework.context.ApplicationContext; |
| import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
| import org.testng.annotations.Test; |
|
| public class MyTest { |
| @Test |
| public void test(){ |
| //如果完全使用了配置类方法去做,我们就只能通过AnnotationConfig上下文去获取容器,通过配置类的class对象加载! |
| ApplicationContext context = new AnnotationConfigApplicationContext(XiaConfig.class); |
| User getUser = context.getBean("getUser", User.class); |
| System.out.println(getUser.toString()); |
| } |
| } |
| ``` |
|
| 这种纯Java的配置在SpringBoot随处可见 |
|
| # 10、 代理模式 |
|
| 为什么要学习代理模式?因为这就是SpringAOP的底层! |
|
| ## 10.1、 静态代理 |
|
| 角色分析: |
|
| - 抽象角色:一半会使用接口或者抽象类来解决 |
| - 真实角色:被代理的角色 |
| - 代理角色:代理真实角色,代理真是角色后,我们一般会做一些附属操作 |
| - 客户:访问代理对象的人! |
|
| 代码步骤: |
|
| 1. 接口 |
|
| ```java |
| public interface Rent { |
| void rent(); |
| } |
| ``` |
|
| 2. 真实角色 |
|
| ```java |
| public class Master implements Rent{ |
| public void rent() { |
| System.out.println("房东出租房子"); |
| } |
| } |
| ``` |
|
| 3. 代理角色 |
|
| ```java |
| public class Proxy implements Rent { |
|
| private Master master; |
|
| public Master getMaster() { |
| return master; |
| } |
|
| public void setMaster(Master master) { |
| this.master = master; |
| } |
|
| public void rent() { |
| master.rent(); |
| } |
|
| public void seeHouse(){ |
| System.out.println("看房"); |
| } |
|
| public void fee(){ |
| System.out.println("收中介费"); |
| } |
|
| public void heTong(){ |
| System.out.println("签合同"); |
| } |
| } |
| ``` |
|
| 4. 客户端访问代理角色 |
|
| ```java |
| public class MyTest { |
| public static void main(String[] args) { |
| Master master = new Master(); |
| Proxy proxy = new Proxy(); |
| proxy.setMaster(master); |
| proxy.seeHouse(); |
| proxy.rent(); |
| proxy.heTong(); |
| proxy.fee(); |
| } |
| } |
| ``` |
|
| 代理模式的好处: |
|
| - 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务 |
| - 公共业务交给代理角色!实现了业务的分工! |
| - 公共业务发生扩展的时候,方便集中管理! |
|
| 缺点: |
|
| - 一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率变低。 |
|
| ## 10.2、 加深理解 |
|
| 1. 接口 |
|
| ```java |
| public interface UserService { |
| void add(); |
| void delete(); |
| void update(); |
| void query(); |
| } |
| ``` |
|
| 2. Service层 |
|
| ```java |
| 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 query() { |
| System.out.println("查询用户"); |
| } |
| } |
| ``` |
|
| 3. 代理 |
|
| ```java |
| public class UserServiceProxy implements UserService { |
|
| private UserServiceImpl userService; |
|
| public UserServiceImpl getUserService() { |
| return 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. 客户端 |
|
| ```java |
| public class Client { |
| public static void main(String[] args) { |
| UserServiceImpl userService = new UserServiceImpl(); |
| UserServiceProxy proxy = new UserServiceProxy(); |
| proxy.setUserService(userService); |
| proxy.add(); |
| proxy.update(); |
| proxy.delete(); |
| proxy.query(); |
| } |
| } |
| ``` |
|
|
|
| ## 10.3、 动态代理 |
|
| - 动态代理和静态代理角色一样 |
| - 动态代理的代理类是动态生成的,不是我们直接写好的! |
| - 动态代理分为两大类:基于接口的动态代理,基于类的动态代理 |
| - 基于接口 |
| - 基于类: cglib |
| - java字节码实现: javasist |
|
|
|
| 需要了解两个类: Proxy: 代理, InvocationHandler: 调用处理程序 |
|
| 动态代理的好处: |
|
| - 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务 |
| - 公共业务交给代理角色!实现了业务的分工! |
| - 公共业务发生扩展的时候,方便集中管理! |
| - 一个动态代理类代理的是一个接口,一般就是对应的一类业务 |
| - 一个动态代理类可以代理多个类,只要是实现了同一个接口即可 |
|
| ```java |
| import java.lang.annotation.Target; |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
|
| 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(), |
| this.target.getClass().getInterfaces(),this); |
| } |
|
| public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
| log(method.getName()); |
| Object result = method.invoke(target); |
| return result; |
| } |
|
| public static void log(String msg){ |
| System.out.println("执行了"+msg+"方法"); |
| } |
| } |
| ``` |
|
| 测试 |
|
| ```java |
| 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.rent(); |
| } |
| } |
| ``` |
|
|
|
| # 11、 AOP |
|
| ## 11.1、 什么是AOP |
|
| AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 |
|
| ## 11.2、 AOP在Spring中的作用 |
|
| 提供声明式事务;允许用户自定义切面 |
|
| - 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等。。。 |
| - 切面(ASPECT):横切关注点被模块化的特殊对象,即,他是一个类。 |
| - 通知(Advice):切面必须要完成的工作。即,他是类中的一个方法。 |
| - 目标(Target):被通知的对象。 |
| - 代理(Proxy):向目标对象应用通知之后创建的对象。 |
| - 切入点(PointCut):切面通知执行的“地点”的定义。 |
| - 连接点(JointPoint):与切入点匹配的执行点。 |
|
| SpringAOP中,通过Advice定义横切逻辑。Spring中支持5种类型的Advice: |
|
| 即AOP在不改变原有代码的情况下,去增加新的功能。 |
|
|
|
| ## 11.3、 使用Spring实现AOP |
|
| 【重点】使用AOP织入,需要导入一个依赖包! |
|
| ```xml |
|
|
| org.aspectj |
| aspectjweaver |
| 1.9.6 |
|
| ``` |
|
| 方式一: 使用Spring 的 API 接口 |
|
| 1. 实现AfterReturningAdvice接口 |
|
| ```java |
| import org.springframework.aop.AfterReturningAdvice; |
|
| import java.lang.reflect.Method; |
|
| public class AfterLog implements AfterReturningAdvice { |
| public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { |
| System.out.println(target.getClass().getName()+"类的"+method.getName()+"方法的返回结果为:"+returnValue); |
| } |
| } |
| ``` |
|
| 2. 实现MethodBeforeAdvice接口 |
|
| ```java |
| import org.springframework.aop.MethodBeforeAdvice; |
|
| import java.lang.reflect.Method; |
|
| public class Log implements MethodBeforeAdvice { |
| public void before(Method method, Object[] args, Object target) throws Throwable { |
| System.out.println(target.getClass().getName()+"类的"+method.getName()+"方法被执行了"); |
| } |
| } |
| ``` |
|
| 3. 注册配置文件 |
|
| ```xml |
|
| <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"> |
|
|
|
|
|
|
|
| aop:config |
|
| <aop:pointcut id="pointcut" expression="execution(* com.xia.service.UserServiceImpl.*())"/> |
|
| <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor> |
| <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor> |
| </aop:config> |
|
| ``` |
|
| 4. 测试 |
|
| ```java |
| import com.xia.service.UserService; |
| import org.springframework.context.ApplicationContext; |
| import org.springframework.context.support.ClassPathXmlApplicationContext; |
| import org.testng.annotations.Test; |
|
| public class MyTest { |
| @Test |
| public void myTest(){ |
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); |
| UserService userService = context.getBean("userServiceImpl", UserService.class); |
| userService.query(); |
| } |
| } |
| ``` |
|
| 方式二: 使用自定义类来实现AOP |
|
| 定义接口 |
|
| ```java |
| public class DiyPointCut { |
|
| public void after() { |
| System.out.println("方法执行后"); |
| } |
|
| public void before() { |
| System.out.println("方法执行前"); |
| } |
|
| } |
| ``` |
|
| 配置 |
|
| ```xml |
|
| <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"> |
|
|
|
|
|
|
|
|
| aop:config |
|
| <aop:aspect ref="diy"> |
|
| <aop:pointcut id="point" expression="execution(* com.xia.service.UserServiceImpl.*(..))"/> |
|
| <aop:after method="after" pointcut-ref="point"></aop:after> |
| <aop:before method="before" pointcut-ref="point"></aop:before> |
| </aop:aspect> |
| </aop:config> |
|
| ``` |
|
| 方式三: 使用注解实现 |
|
| 编写AnnotationPointCut类 |
|
| ```java |
| 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; |
|
| @Aspect |
| public class AnnotationPointCut { |
|
| @Before("execution(* com.xia.service.UserServiceImpl.*(..))") |
| public void before(){ |
| System.out.println("方法执行前"); |
| } |
|
| @After("execution(* com.xia.service.UserServiceImpl.*(..))") |
| public void after(){ |
| System.out.println("方法执行后"); |
| } |
|
| //在环绕增强中,我们可以给定一个参数,代表我们要获取处理的切入点 |
| @Around("execution(* com.xia.service.UserServiceImpl.*(..))") |
| public void around(ProceedingJoinPoint joinPoint) throws Throwable { |
| System.out.println("环绕前"); |
| joinPoint.proceed(); |
| System.out.println("环绕后"); |
| } |
|
| } |
| ``` |
|
| 开启注解支持 |
|
| ```xml |
|
| <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"> |
|
|
|
|
|
|
|
|
| aop:aspectj-autoproxy/ |
|
|
| ``` |
|
| # 12、 整合Mybaits |
|
| ## 12.1、 回忆Mybatis |
|
| ## 12.2、 Mybatis-Spring |
|
| 1. 编写数据源配置 |
|
| ```xml |
|
|
|
|
|
|
| ``` |
|
| 2. SqlSessionFactory |
|
| ```xml |
|
|
|
|
|
|
| ``` |
|
| 3. SqlSessionTemlate |
|
| ```xml |
|
|
|
|
| ``` |
|
| 4. 需要给接口加实现类 |
|
| ```java |
| import org.mybatis.spring.SqlSessionTemplate; |
|
| import java.util.List; |
|
| public class UserMapperImpl implements UserMapper { |
| //我们所有的操作,都是用SqlSessionTemplate来执行, |
|
| private SqlSessionTemplate sqlSession; |
|
| public void setSqlSession(SqlSessionTemplate sqlSession) { |
| this.sqlSession = sqlSession; |
| } |
|
| public int delete(int id) { |
| return 0; |
| } |
|
| public int add(User user) { |
| return 0; |
| } |
|
| public List query() { |
| return sqlSession.getMapper(UserMapper.class).query(); |
| } |
| } |
| ``` |
|
| ```xml |
|
|
|
| ``` |
|
| 5. 测试 |
|
| ```java |
| import com.xia.mapper.UserMapperImpl; |
| import com.xia.pojo.User; |
| import org.springframework.context.ApplicationContext; |
| import org.springframework.context.support.ClassPathXmlApplicationContext; |
| import org.testng.annotations.Test; |
|
| import java.util.List; |
|
| public class MyTest { |
|
| @Test |
| public void queryTest() { |
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); |
| UserMapperImpl userMapper = context.getBean("userMapperImpl", UserMapperImpl.class); |
| List userList = userMapper.query(); |
| for (User user : userList) { |
| System.out.println(user); |
| } |
| } |
| } |
| ``` |
|
|
|
| 继承SqlSessionDaoSupport 实现 |
|
| ```java |
| package com.xia.mapper; |
|
| import com.xia.pojo.User; |
| import org.mybatis.spring.support.SqlSessionDaoSupport; |
|
| import java.util.List; |
|
| public class UserMapperImplTwo extends SqlSessionDaoSupport implements UserMapper { |
|
| public List query() { |
| return getSqlSession().getMapper(UserMapper.class).query(); |
| } |
|
| public int delete(int id) { |
| return 0; |
| } |
|
| public int add(User user) { |
| return 0; |
| } |
| } |
| ``` |
|
| 配置bean |
|
| ```xml |
|
|
|
| ``` |
|
| 测试 |
|
| ```java |
| import com.xia.mapper.UserMapper; |
| import com.xia.mapper.UserMapperImplTwo; |
| import com.xia.pojo.User; |
| import org.springframework.context.ApplicationContext; |
| import org.springframework.context.support.ClassPathXmlApplicationContext; |
| import org.testng.annotations.Test; |
|
| import java.util.List; |
|
| public class MyTest { |
|
| @Test |
| public void queryTest() { |
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); |
| UserMapper userMapper = context.getBean("userMapperImplTwo", UserMapper.class); |
| List userList = userMapper.query(); |
| for (User user : userList) { |
| System.out.println(user); |
| } |
| } |
| } |
| ``` |
|
|
|
| # 13、 声明式事务 |
|
| ## 13.1、 事务回顾 |
|
| - 把一组业务当作一个业务来做,要么都成功,要么都失败 |
| - 事务在项目开发中,十分重要,涉及到数据的一致性问题,不能马虎! |
| - 确保完整性和一致性! |
|
|
|
| 事务的ACID原则: |
|
| - 原子性 |
| - 一致性 |
| - 隔离性 |
| - 多个业务可能操作同一个资源,互相隔离,防止数据损坏 |
| - 持久性 |
| - 事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的写到存储器中 |
|
| ## 13.2、 Spring中的事务管理 |
|
| - 声明式事务: AOP |
| - 编程式事务: 需要在代码中,进行事务管理 |
|
| 思考 |
|
| |
|
| - 如果不配置事务,可能存在数据提交不一致的情况: |
| - 如果我们不在Spring中配置声明式事务,我们就需要到代码中手动配置事务 |
| - 事务在项目开发中十分重要,涉及到数据的一致性和完整性问题,不能马虎。 |
|
| ```xml |
|
|
|
|
|
|
| <tx:advice id="txAdvice" transaction-manager="transactionManager"> |
| tx:attributes |
|
| <tx:method name="*" propagation="REQUIRED"/> |
| </tx:attributes> |
| </tx:advice> |
|
| aop:config |
| <aop:pointcut id="txPointcut" expression="execution(* com.xia.mapper..(..))"/> |
| <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> |
| </aop:config> |
| ``` |