1 、Spring

1.1 简介

  1. Spring理念:使现有的技术更加容易使用,本身是个大杂烩,整合了现有的技术框架

  2. SSH ->Stucts2+Spring+Hibernate || SSM->SpringMVC+Spring+Mybatis

  3. 下载方式:

1.2 优点

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

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

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

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

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

1.3 组成

在这里插入图片描述

1.4扩展

现代化的Java开发

image-20220625143415049

​ 构建一切-(SpringBoot)–>协调一切(Spring Cloud)—>连接一切(Spring Cloud Data Folw)

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

因为大多数的公司使用SpringBoot快速开发,学习SpringBoot的前提就是学习Spring和SpringMVC

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

2、IOC的推导

  1. UserDao接口

  2. UserDaoImpl接口的实现类

  3. UserService业务接口

  4. UserServiceImpl业务实现类

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

    我们去用一个Set接口来实现

    1
    2
    3
    4
    5
    private UserDao userDao;
    //利用Set进行动态实现值的注入!
    public void setUserDao(UserDao userDao){
    this.userDao=userDao;
    }
    • 之前,程序是主动创建对象!控制权在程序员手中
    • 使用了Set注入后,程序不再具有主动性,而是变成被动的接收对象

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

    image-20220625160535895

image-20220625160905779

image-20220626153221283

3、HelloSpring

4、IOC创建对象的方式、

  1. 使用无参构造创建对象(默认)

  2. 假设要使用有参构造方法

    1. 下标赋值 <constructor-arg index="下表数" value="下标值"/>
    2. 通过类型创建(不推荐): <constructor-arg type="java.lang.String" value="张锋学JAVA"/>
    3. 直接通过参数名来设置:
    1
    2
    3
    <bean id="User" class="com.zhang.pojo.User">
    <constructor-arg name="name" value="张锋学JAVA"/>
    </bean>

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

5、Spring配置

  1. 别名

    1
    2
    <!--如果添加了别名可以用别名来获取对象-->
    <alias name="User" alias="userasd"/>
  2. Bean的配置

    1
    2
    3
    4
    5
    6
    7
    8
    <!--
    id:bean的唯一标识符,也就是我们所说的对象名
    class:bean对象对应的全限定名:包名+类型
    name:也是别名
    -->
    <bean id="userF" class="com.zhang.pojo.User" name="user3,u3">
    <constructor-arg value="zf牛逼"/>
    </bean>
  3. import

    一般运用于团队开发,可以将多个配置文件合并成一个

    假设,现在一个项目由多人开发,这三个人复制不同类的开发,不同的类需要注册在不同的bean’中,我们可以利用,import将所有人的bean.xml合并成一个总的,最后使用的时候直接配置总的就好

    • 张三

    • 李四

    • 王五

    • applicationContext.xml

      1
      2
      3
      4
      5
      <import resource="beans.xml1"/>
      <import resource="beans.xml2"/>
      <import resource="beans.xml3"/>


6、依赖注入

  1. 构造器注入

    前面说过了

  2. Set方式注入

    • 依赖注入:Set注入

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

    【环境搭建】

    ​ 1.复杂环境

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package com.zhang.pojo;

    public class Address {
    private String address;

    public String getAddress() {
    return address;
    }

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

    ​ 2.真实测试对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Student {
    private String name;
    private Address address;
    private String book[];
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private Properties info;
    private String wife;

    3.beans

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?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.xsd">

    <!-- 普通注入-->
    <bean id="Student" class="com.zhang.pojo.Student">
    <property name="name" value="张锋"/>
    </bean>
    </beans>

    4,测试类

    1
    2
    3
    4
    5
    6
    7
    public class Mytest {
    public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Student student = (Student)context.getBean("Student");
    System.out.println(student.getAddress());
    }
    }
    1. 普通注入
    1
    2
    3
    4
    <bean id="address" class="com.zhang.pojo.Address"/>
    <bean id="Student" class="com.zhang.pojo.Student">
    <!--普通注入-->
    <property name="name" value="张锋"/>

    2.数组注入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!--数组-->
    </property>
    <property name="book">
    <array>
    <value>红楼梦</value>
    <value>西游记</value>
    <value>水浒传</value>
    </array>
    </property>

​ 3.List注入

1
2
3
4
5
6
7
<!--List注入-->
<property name="card">
<map>
<entry key="身份证" value="130922"/>
<entry key="银行卡" value="123123"/>
</map>
</property>

​ 4.set注入

1
2
3
4
5
6
7
<property name="games">
<set>
<value>LOL</value>
<value>COC</value>
<value>DNF</value>
</set>
</property>

5 空值注入

1
2
3
<property name="wife">
<null/>
</property>

6 properties注入

1
2
3
4
5
6
7
<!--properties注入-->
<property name="info">
<props>
<prop key="学号">20201308092</prop>
<prop key="年龄">20</prop>
</props>
</property>

3.拓展注入

4.bean的作用域

① singleton

使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。

② prototype

使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。

③ request

该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。

④ session

该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。

⑤ global-session

该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。

5.bean的自动装配

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

  2. byName的自动装配:

    1
    2
    3
    4
    5
    <bean id="cat" class="com.zhang.pojo.cat"/>
    <bean id="dog" class="com.zhang.pojo.dog"/>
    <bean id="people" class="com.zhang.pojo.people" autowire="byName">
    <property name="name" value="张锋"/>
    </bean>

    3.byType的自动装配:

    1
    2
    3
    4
    5
    6
    <!--byName:会自动再容器上下文中查找,和自己对象类型后面的值对应的bean-->
    <bean id="cat1111" class="com.zhang.pojo.cat"/>
    <bean id="dog1111" class="com.zhang.pojo.dog"/>
    <bean id="people" class="com.zhang.pojo.people" autowire="byType">
    <property name="name" value="张锋"/>
    </bean>

    小结

  • byName:需要保证所有的bean的id唯一,并且这个bean和需要自动注入的属性set方法的值一致

  • byType:需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性类型一致

    6.使用注解实现自动装配

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

    测试代码:

    1
    2
    3
    4
    5
    private String name;
    @Autowired(required = false)//如果Autowired后面的required属性为false,说明这个对象可以null,否则不允许为空
    private cat cat;
    @Autowired
    private dog dog;

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

    测试代码:

    1
    2
    3
    4
    5
    6
    7
    private String name;
    @Autowired(required = false)
    @Qualifier(value = "cat222")
    private cat cat;
    @Autowired
    @Qualifier(value = "dog222")
    private dog dog;

7、Spring注解开发

1.自动装配配置

@autowired :通过类型和名字进行自动装配,如果autowired不能唯一自动装配上属性,则需要通过@Qualifier(value=”xxx”)

@Nullable:字段标记了这个注解,说明这个字段可以是Null

@Resource 通过名字类型自动装配

@Component:组件,放在类上,说明这个类被Spring管理了,就是bean

2.属性如何注入

1
2
3
4
5
6
7
8
9
@Component //组件
public class User {
public String name;

@Value("张锋")//相当于<property name="name" value="张锋">
public void setName(String name) {
this.name = name;
}
}

3.衍生注解

@Component有几个衍生注解,我们在Web开发中,会按照MVC三层架构进行分层

  • dao [@Repository ]
  • service[@Sercive]
  • controller[ ]

4.作用域

1
2
3
4
5
6
7
8
9
10
@Component //组件
@Scope("singleton")
public class User {
public String name;

@Value("张锋")//相当于<property name="name" value="张锋">
public void setName(String name) {
this.name = name;
}
}

5.小结

XML与注解

  • xml更加万能,适用于更多场合,维护简单方便
  • 注解不是自己的类用不了,维护相对复杂
  • XML用来管理bean
  • 注解只用来管理属性的注入

8、代理模式

为何要学习代理模式:代理模式是SpringAOP的底层

代理的分类:静态代理和动态代理

1.静态代理

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

2.动态代理

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

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

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

  • 基于接口的动态代理:JDK的动态代理
  • 基于类的动态代理:cglib
  • JAVA字节码实现:javassist

了解两个类:Proxy 代理 ,invocationHandler:调用处理程序

  • 动态代理的基本代码

    ProxyInvocationHandler类的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import java.lang.reflect.Proxy;

    //用这个类自动生成代理类
    public class ProxyInvocationHandler implements InvocationHandler {

    private Object object;
    public void SetTarget(Object object){
    this.object=object;
    }
    public Object getProxy( ){
    return Proxy.newProxyInstance(this.getClass().getClassLoader(),object.getClass().getInterfaces(),this );
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    log(method.getName());
    Object invoke = method.invoke(object, args);
    return invoke;
    }
    public void log(String msg){
    System.out.println("调用了一个"+msg+"方法");
    }
    }

应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
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();

}
}

3、AOP(面向切面编程)

  1. 使用Spring实现AOP

    ​ xml中配置文件头:

    1
    2
    3
    4
    5
    6
    7
    8
    <?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.xsd
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd">
    1. ​ 方法1:原生的Spring API接口

      1. 以创建日志为例: 两个日志类为:Log和AfterLog

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        package com.zhang.demo1;
        import org.springframework.aop.MethodBeforeAdvice;
        import java.lang.reflect.Method;
        public class log implements MethodBeforeAdvice {
        //method要执行的目标的对象方法
        //Object:参数
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"的方法被执行了");
        }
        }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package com.zhang.demo1;

    import org.springframework.aop.AfterAdvice;
    import org.springframework.aop.AfterReturningAdvice;

    import java.lang.reflect.Method;

    public class AfterLog implements AfterReturningAdvice {

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

​ ApplicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--注册bean-->
<bean id="userService" class="com.zhang.demo1.UserServiceImpl"></bean>
<bean id="log" class="com.zhang.demo1.log"></bean>
<bean id="AfterLog" class="com.zhang.demo1.AfterLog"></bean>
<!--Aop的配置-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.zhang.demo1.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="AfterLog" pointcut-ref="pointcut"/>
</aop:config>


</beans>

测试类:

1
2
3
4
5
6
7
8
9
10
11
import com.zhang.demo1.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.query();

}
}

输出结果

image-20220903222502218

第二种方法:自定义切点法

​ 自定义切点类 DiyPointCut

1
2
3
4
5
6
7
8
9
10
package com.zhang.demo1;

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

配置文件:ApplicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--注册bean-->
<bean id="UserService" class="com.zhang.demo1.UserServiceImpl"/>
<bean id="Diypoint" class="com.zhang.demo1.DiyPointCut"></bean>
<aop:config>
<!--自定义切面,ref要引用的类-->
<aop:aspect ref="Diypoint">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.zhang.demo1.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>

</aop:aspect>
</aop:config>

</beans>

​ 输出结果:

image-20220903222428048

​ AOP原理如图:

image-20220903221040246

9、Mybatis-Spring

​ 项目结构

image-20220917224033000

  1. 编写数据源配置

    1
    2
    3
    4
    5
    6
    <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/user?useSSL=false&amp;allowPublicKeyRetrieval=true"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
    </bean>
  2. sqlSessionFactory

1
2
3
4
5
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/zhang/mapper/*.xml"/>
</bean>
  1. sqlSessionTemplate
1
2
3
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
  1. 需要给接口加实现类
1
2
3
4
5
6
7
8
9
10
11
public class UserMapperImp implements UserMapper{
private SqlSessionTemplate sqlSession;

public List<U> QueryAllUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.QueryAllUser();
}

public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}

10、声明式事务

1、回顾事务

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

事务的ACID原则:

  • 原子性
  • 一致性
  • 隔离性

​ 多个业务放到同一个资源防止数据破坏

  • 持久性

​ 事务一旦提交,无论发生什么问题,结果都不会在被影响,被持久化写道存储器中