SSM框架

 Spring:

架构分为:单一应用架构,垂直应用架构,分布式架构,流动计算架构。

Spring是一个轻量级的开源框架。

Spring为了解决企业级应用的开发逻辑层和其他层的耦合问题。

Spring是一个IOCAOP的容器框架。

IOC:控制反转

AOP:面向切面编程

容器:包含并管理应用对象的生命周期

使用Spring的优点:

  1.Spring通过DI,AOP和消除样板式代码来简化企业级Java开发

  2.Spring框架之外还存在一个创建在核心框架之上的庞大的生态圈上,它将Spring扩展到不同领域,如Web服务,REST,移动开发以及NoSQL

  3.低入侵式设计,代码的污染极低

  4.独立于各种应用服务器,基于Spring框架的应用,可以真正的实现Writh Once,RunAnywhere的承诺

  5.Spring的Ioc容器降低了业务对象替换的复杂性,提高了组建的之间的解耦

  6.Spring的Aop允许将一些通过任务如安全,事务,日志等进行集中式处理,从而提供了更好的复用

  7.Spring的ORM和DAO提供了与第三方持久性的框架的良好的整合,并简化了底层的数据库访问

  8.Spring的高度开发性,并不强制应用完全依赖与Spring,开发者可自由选用Spring框架的部分或全部

Spring :   ioc  /   aop

IOC的代码实现(三种方式):

1.导入jar包 ---配置xml文件v

2.maven+注解+xml文件

3.springboot+javaconfig

IOC的优点:

1.解耦

2.集中管理

3.功能可复用(减少对象的创建和内存的消耗)

4.使得整个程序的体系的结构可维护性,灵活性,扩展性变高。

Ioc和Di严谨的来说 本质上有一些区别,Ioc是从容器的角度来写而Di是从程序上的角度来写。

Spring总结
1.简介
1.1.简介
简介
Spring : 春天 —>给软件行业带来了春天
2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
很难想象Rod Johnson的学历 , 他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术
官网 : http://spring.io/
官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/
GitHub : https://github.com/spring-projects
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.0.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.0.RELEASE</version> </dependency>
1.2.优点
优点
1、Spring是一个开源免费的框架 , 容器 .
2、Spring是一个轻量级的框架 , 非侵入式的 .
3、控制反转 IoC , 面向切面 Aop
4、对事物的支持 , 对框架的支持
一句话概括:
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
1.3.组成
组成
 
在这里插入图片描述
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 .
 
在这里插入图片描述
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
  • 核心容器
  • :核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用
  • 控制反转
  • (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring 上下文
  • :Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP
  • :通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO
  • :JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM
  • :Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块
  • :Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架
  • :MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
1.4.扩展
拓展
Spring Boot与Spring Cloud
  • Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;
  • Spring Cloud是基于Spring Boot实现的;
  • Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
  • Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
  • SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。
 
在这里插入图片描述
2.IOC理论推导
IoC基础
新建一个空白的maven项目
2.1.分析实现
分析实现
我们先用我们原来的方式写一段代码 .
1、先写一个UserDao接口
public interface UserDao { public void getUser(); }
2、再去写Dao的实现类
public class UserDaoImpl implements UserDao { @Override public void getUser() { System.out.println("获取用户数据"); } }
3、然后去写UserService的接口
public interface UserService { public void getUser(); }
4、最后写Service的实现类
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); @Override public void getUser() { userDao.getUser(); } }
5、测试一下
@Test public void test(){ UserService service = new UserServiceImpl(); service.getUser(); }
这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下 .
把Userdao的实现类增加一个 .
public class UserDaoMySqlImpl implements UserDao { @Override public void getUser() { System.out.println("MySql获取用户数据"); } }
紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoMySqlImpl(); @Override public void getUser() { userDao.getUser(); } }
在假设, 我们再增加一个Userdao的实现类 .
public class UserDaoOracleImpl implements UserDao { @Override public void getUser() { System.out.println("Oracle获取用户数据"); } }
那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .
那我们如何去解决呢 ?
我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 .
public class UserServiceImpl implements UserService { private UserDao userDao; // 利用set实现 public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void getUser() { userDao.getUser(); } }
现在去我们的测试类里 , 进行测试 ;
@Test public void test(){ UserServiceImpl service = new UserServiceImpl(); service.setUserDao( new UserDaoMySqlImpl() ); service.getUser(); //那我们现在又想用Oracle去实现呢 service.setUserDao( new UserDaoOracleImpl() ); service.getUser(); }
大家发现了区别没有 ? 可能很多人说没啥区别 . 但是同学们 , 他们已经发生了根本性的变化 , 很多地方都不一样了 . 仔细去思考一下 , 以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .
这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !
2.2.IOC本质
IOC本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
在这里插入图片描述
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
 
在这里插入图片描述
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
3.HelloSpring
导入Jar包
注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 .
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.10.RELEASE</version> </dependency> 12345
编写代码
1、编写一个Hello实体类
public class Hello { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void show(){ System.out.println("Hello,"+ name ); } }
2、编写我们的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"> <!--bean就是java对象 , 由Spring创建和管理--> <bean id="hello" class="com.kuang.pojo.Hello"> <property name="name" value="Spring"/> </bean> </beans>
3、我们可以去进行测试了 .
@Test public void test(){ //解析beans.xml文件 , 生成管理相应的Bean对象 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); //getBean : 参数即为spring配置文件中bean的id . Hello hello = (Hello) context.getBean("hello"); hello.show(); }
思考
  • Hello 对象是谁创建的 ? hello 对象是由Spring创建的
  • Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的
这个过程就叫控制反转 :
  • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .
修改案例一
我们在案例一中, 新增一个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"> <bean id="MysqlImpl" class="com.kuang.dao.impl.UserDaoMySqlImpl"/> <bean id="OracleImpl" class="com.kuang.dao.impl.UserDaoOracleImpl"/> <bean id="ServiceImpl" class="com.kuang.service.impl.UserServiceImpl"> <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写--> <!--引用另外一个bean , 不是用value 而是用 ref--> <property name="userDao" ref="OracleImpl"/> </bean> </beans>
测试!
@Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl"); serviceImpl.getUser(); }
OK , 到了现在 , 我们彻底不用再程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !
3.IOC创建对象的方式
1,使用无参构造创建对象,默认!
2,假设我们要使用有参构造创建对象
1,下标赋值
<bean id="index" class="com.han.pojo.User"> <constructor-arg index="0" value="王晓涵"/> </bean>
2,类型
<bean id="type" class="com.han.pojo.User"> <constructor-arg type="java.lang.String" value="王晓涵"/> </bean>
3,参数名
<bean id="name" class="com.han.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.han.pojo.User" name="user3 user4,user5;user6"> <property name="name" value="王肖寒"/> </bean>
5.3 import
这个import,一般用于团队开发使用的,它可以将多个配置文件,导入合并为一个
假设,现在这个项目中有多个人开发,这三个人复制不同的类开发,不同的类开发需要注册在不同的bean总我们可以用一个import将所有人的bean.xml合并成一个总的!
·张三
·李四
·王五
·applicationContext.xml
<import resource="beans.xml"/>
使用的时候,直接使用总的配置就可以啦
 
6,DI 依赖注入
6.1 构造器注入
前面有
6.2 Set方式注入【重点】
·依赖注入:set注入
依赖:bean对象的创建依赖于容器
注入:bean对象中的所有属性,由容器来注入!
【环境搭建】
1.复杂类型
 
package com.han.pojo; public class Address { private String Address; public String getAddress() { return Address; } public void setAddress(String address) { Address = address; } public Address() { } public Address(String address) { Address = address; } @Override public String toString() { return "Address{" + "Address='" + Address + '\'' + '}'; } }
2.真实测试环境
public class Student { 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;
3.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.han.pojo.Student"> <!-- 第一种普通注入值 --> <property name="name" value="王晓涵"/> </bean> </beans>
4.测试类
 
 
<?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.han.pojo.Address"> <property name="address" value="郑州"/> </bean> <bean id="student" class="com.han.pojo.Student"> <!-- 第一种 普通注入值 --> <property name="name" value="王晓涵"/> <!-- 第二种 Bean注入 --> <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="12345678901223"/> <entry key="银行卡" value="12345678901223"/> </map> </property> <!-- set--> <property name="games"> <set> <value>极品钢琴</value> </set> </property> <!-- null (设置空值)--> <property name="wife"> <null/> </property> <!-- Properties --> <property name="info"> <props> <prop key="1">cpdd</prop> <prop key="2">dddd</prop> </props> </property> </bean> </beans>
 
6.3 拓展方式注入
我们可以使用p命名空间和c命名空间进行注入!
User.java :【注意:这里没有有参构造器!】
public class User { private String name; private int age; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
1、P命名空间注入 : 需要在头文件中加入约束文件
导入约束 : xmlns:p="http://www.springframework.org/schema/p" <!--P(属性: properties)命名空间 , 直接注入属性--> <bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
2、c 命名空间注入 : 需要在头文件中加入约束文件
导入约束 : xmlns:c="http://www.springframework.org/schema/c" <!--C(构造: Constructor)命名空间 , 使用构造器注入--> <bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>
发现问题:爆红了,刚才我们没有写有参构造!
解决:把有参构造器加上,这里也能知道,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.han.pojo.User" p:age="12" p:name="王晓涵"/> <!-- c:命名空间 通过构造器注入:constructor-arg --> <bean id="user2" class="com.han.pojo.User" c:age="12" c:name="王晓涵o" /> </beans>
测试代码:
@Test public void show(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); User user = context.getBean("user2", User.class); System.out.println(user.toString()); }
注意点:p命名空间和c命名空间不能直接使用,需要导入xml约束
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
6.4 bean的作用域
在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象 .
xml
1.单例模式(Spring默认机制)
<bean id="user" class="com.han.pojo.User" p:age="12" p:name="王晓涵" scope="singleton"/>
2.原型模式:每次从容器中get的时候,都会产生一个新的对象!
<bean id="user2" class="com.han.pojo.User" c:age="12" c:name="王晓涵o" scope="prototype"/>
3.其余的request,session,application,这些个只能在web开发中使用到!
7 Bean的自动装配
·自动装配是Spring满足Bean以来的一种方式!
·Spring会在上下文中自动寻找并自动给Bean转配属性!
在Spring中会有三种装配的方式
1.在xml中显示的配置
2.在Java中显示配置
3.隐式的自动装配Bean【重要】
7.1 测试
环境搭建:一个人有两个宠物
7.2 ByName自动装配
<?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"> <bean id="cat" class="com.han.pojo.Cat"/> <bean id="dog" class="com.han.pojo.Dog"/> <!-- byName:会在自动在容器上下文查找,会和自己set后面的值进行比较对应 bean id --> <bean id="people" class="com.han.pojo.People" autowire="byName"> <property name="name" value="王肖寒"/> </bean> </beans>
7.3 ByType自动装配
<?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"> <bean id="cat" class="com.han.pojo.Cat"/> <bean id="dog22" class="com.han.pojo.Dog"/> <!-- byName:会在自动在容器上下文查找,会和自己set后面的值进行比较对应 beanid --> <bean id="people" class="com.han.pojo.People" autowire="byName"> <property name="name" value="王肖寒"/> </bean> <!-- byType:会在自动在容器上下文查找,会和自己属性类型相同的值进行比较对应 bean (必须保证值唯一 不然会报错!) --> <bean id="people2" class="com.han.pojo.People" autowire="byType"> <property name="name" value="王肖寒"/> </bean> </beans>
小结:
byName的时候,需要保证bean的id唯一,并且这个bean需要和自动注入的属性set的方法的值一致!
byType的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性类型一致!
7.4 使用注解实现自动装配
jdk1.5支持的注解,Spring2.5就支持注解了。
准备工作:利用注解的方式注入属性。
1、在spring配置文件中引入context文件头
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
2、开启属性注解支持!
<context:annotation-config/>
@Autowired
直接在属性上使用即可!也可以在set方式上使用!
使用Autowired我们就可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,并且符合名字ByName!
科普:
1.
 
public class SimpleMovieLister { @Autowired public void setMovieFinder(@Nullable MovieFinder movieFinder) { ... } } @Nullable 字段标记了这个注解,说明这个字段可以为null
2.
public @interface Autowired { boolean required() default true; }
测试代码:
// 如果定义了Autowired的required为false 就代表这个对象可以为null,否则不可以为空 @Autowired(required = false) private Cat cat; @Autowired private Dog dog; private String name;
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们
可以使用@Qualifier(vaule="xxx")去配置@Autowired的使用,指定一个唯一的bean对象注入!
 
@Autowired private Cat cat; @Autowired @Qualifier("dog11") private Dog dog; private String name;
@Resource注解
@Resource(name = "cat") private Cat cat; @Resource private Dog dog; private String name;
小结:
@Resource和@Autowired的区别:
都是用来自动装配的都可以放在属性字段上
@Autowired通过byType的方式实现
@Resource默认通过byname的方式实现,如果找不到名字则通过byType实现!如果两种方式都找不到就报错。
执行顺序不同: @Autowired通过byType的方式实现。 @Resource默认通过byname的方式实现。
 
  • @Autowired是按类型自动转配的,不支持id匹配。
  • 需要导入 spring-aop的包!
8、使用注解开发
在Spring4之后,要使用注解开发,必须保证aop的包导入了
 
xml
使用注解需要导入的context约束,增加注解的支持。
1.bean
2.属性如何注入
package com.han.dao; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import javax.annotation.Resource; //等价于 <bean id="cat" class="com.han.pojo.Cat"/> //@Component 组件 @Component public class User { // 相当于bean里的 <property name="name" value="王肖寒"/> @Value("aa") public String name; }
3.衍生的注解
@Component 有几个衍生注解,我们在web开发中会按照mvc三成架构分层!
dao [@Repository]
service [ @Service ]
controller [ @Controller ]
这四个是注解的功能都是一样的,都代表将某个类注册到Spring中,装配Bean
4.自动装配置
@Autowired 自动装配通过的类型,名字 (如果@Autowired不能自动通过装配那么则需要通过 @Qualifier(value="xxx") ) @Nullable 字段标记了注解,说明这个注解可以为null @Resource 自动装配通过名字,类型
5.作用域
@Component @Scope("xxx") public class User { public String name; // 相当于bean里的 <property name="name" value="王肖寒"/> @Value("aa") public void setName(String name) { this.name = name; } }
 
8.6.小结
xml与注解:
·xml更加万能,适用于任何场合!维护更加简单。
·注解不是自己类是用不了,维护相对复杂!
xml与注解最佳实践:
·xml使用管理bean;
·注解只负责完成属性的注入;
·我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
<context:annotation-config/> <!-- 指定的包下 会自动导入 --> <context:component-scan base-package="com.han.pojo"/>
9.基于Java类进行配置
JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。
测试:
1、编写一个实体类
@Component public class User { private String name; public String getName() { return name; } @Value("A") public void setName(String name) { this.name = name; }
2、新建一个config配置包,编写一个Config配置类
@Configuration @Import(HanConfig.class) //这个也会Spring容器托管 ,注册到容器中 因为他本来就是一个Component @Configuration 代表这个配置类,就和我们之前的bean.xml public class HanConfig { //注册一个bean,就相当于我们之前写的bean标签 //这个方法的名字就相当于bean标签中的id属性 //这个方法的返回值,就相当于bean标签的class属性 @Bean public User getUser(){ return new User();//就是返回要注入到bean的对象! } }
3、测试
//如果完全使用了配置类的方式去做 我进门就只能通过AnnotationConfigApplicationContext 上下文来获取容器 通过配置类的class对象加载 ApplicationContext context= new AnnotationConfigApplicationContext(HanConfig.class); User getUser =(User) context.getBean("getUser"); System.out.println(getUser.getName());
4、成功输出结果!
导入其他配置如何做呢?
1、我们再编写一个配置类!
@Configuration //代表这是一个配置类 public class MyConfig2 { }
2、在之前的配置类中我们来选择导入这个配置类
@Configuration @Import(MyConfig2.class) //导入合并其他配置类,类似于配置文件中的 inculde 标签 public class MyConfig { @Bean public Dog dog(){ return new Dog(); } }
关于这种Java类的配置方式,我们在之后的SpringBoot 和 SpringCloud中还会大量看到,我们需要知道这些注解的作用即可!
10.代理模式
为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP 和 SpringMVC】
代理模式的分类:
·静态代理
·动态代理
10.1 静态代理
角色分析:
·抽象角色:一般会使用接口或者抽象类来解决
·真实角色:被代理的角色
·代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
·客户:访问代理对象的人!
代码步骤:
1.接口
public interface Rent { public void Rent(); }
2.真实角色
public void Rent() { System.out.println("房东要出租房子"); }
 
3.代理角色
package com.han.demo01; public class Proxy implements Rent { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } public void Rent() { host.Rent(); LookHouse(); hetong(); fare(); } public void LookHouse(){ System.out.println("看房"); } public void hetong(){ System.out.println("签合同"); } public void fare(){ System.out.println("收中介费"); } }
4.客户端访问代理角色
public static void main(String[] args) { //房东租房子 Host host=new Host(); //代理 中介帮房东租房子 代理一般会有一些附属属性 Proxy proxy=new Proxy(host); //你不用面会房东 直接找中介即可 proxy.Rent(); }
代理模式的好处
·可以是真实的角色的操作更加纯粹!不会关注一些公共的业务
·公共也就交给代理角色!实现了业务的分工!
·公共业务发生扩展的时候方便集中管理!
缺点:
·一个真实角色就会产生一个代理角色;代码量会翻倍~开发效率会变低~
10.2 加深理解
聊聊AOP:纵向开发,横向开发
 
对应代码在spring-08-proxy
10.3动态代理
·动态代理和静态代理角色一样
·动态代理的代理类是动态生成的,不是我们直接写好的!
·动态代理分为两大类:基于接口的动态代理,基于类的动态代理
·基于接口的--JDK动态代理
·基于类的:cglib
·Java代码字节实现:javasist
两个类:Proxy:代理,InvocationHandler  :调用处理程序
 
 
动态代理的好处:
·可以使用真实角色的操作更加纯粹!不用关注一些公共的业务
·公共也就交给代理的角色!实现了业务的分工!
·公共业务发生扩展的时候,方便集中管理
·一个动态代理类代理的是一个接口,一般就是对应一类业务
·一个动态代理类可以代理多个类,只要实现了多个接口即可。
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织入,需要导入一个依赖包!
<dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> </dependency> </dependencies>
11.3.1.通过 Spring API 实现
实现类:
class UserServiceImpl implements UserService { public void add() { System.out.println("增加了一个用户"); } public void update() { System.out.println("修改一个用户"); } public void delete() { System.out.println("删除一个用户"); } public void query() { System.out.println("查询一个用户"); } }
测试类:
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理的是接口:注意点 UserService userService = context.getBean("userService",UserService.class); userService.delete(); }
第一种方式
使用Spring的API接口【主要是SpringAPI接口实现】
 
增强类:为前置和后置
1.
public class Log implements MethodBeforeAdvice { /** * method:要执行的目标对象的方法 * object:参数 * o:目标对象 * */ public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println(o.getClass().getName()+"的"+method.getName()+"方法被执行了"); } }
2.
public class AfterLog implements AfterReturningAdvice { /** * o:返回值 * */ public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("执行了"+method.getName()+"被执行了"+o); } }
 
首先需要在配置文件里引入类:
<!-- 注册一个id --> <bean class="com.han.service.impl.UserServiceImpl" id="userService"/> <bean class="com.han.log.Log" id="log"/> <bean class="com.han.log.AfterLog" id="afterLog"/>
配置文件:
<!-- 方式一:使用原生的Spring API接口--> <!-- 配置aop : 需要导入aop的约束 --> <aop:config> <!-- <!– 切入点: expression 表达式, execution(要执行的位置!*******)–>--> <aop:pointcut id="pointcut" expression="execution(* com.han.service.impl.UserServiceImpl.*(..))"/> <!-- 执行环绕增加! --> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config>
第二种方式
自定义来实现AOP【主要是切面定义】
1.切入类
public void before() { System.out.println("----------------方法执行前--------------"); } public void after() { System.out.println("----------------方法执行后--------------"); }
2.配置类:
<!-- 方式二:自定义类--> <bean class="com.han.diy.DiyPoinCut" id="cut"/> <aop:config> <!-- 自定义切面:ref 要引用的类 --> <aop:aspect ref="cut"> <!-- 切入点--> <!-- 第一个*任意访问修饰符的方法,第二个*指定类下的所有方法,..代表任意参数--> <aop:pointcut id="point" expression="execution(* com.han.service.*.*(..))"/> <!-- 通知--> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> </aop:config>
第三种方式
使用注解实现
1.注解类
/** * 方式三:使用注解的方式实现AOP * */ @Aspect //标注这个类是一个切面 class AnnotationPoint { @Before("execution(* com.han.service.*.*(..))") public void before(){ System.out.println("---------------在方法之前------------"); } @After("execution(* com.han.service.*.*(..))") public void after(){ System.out.println("---------------在方法之后------------"); } //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点 @Around("execution(* com.han.service.*.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("---------------环绕前------------"); Signature signature = jp.getSignature();//获取签名 System.out.println("signature"+signature); //执行方法 Object proceed = jp.proceed(); System.out.println("---------------环绕后------------"); System.out.println(proceed); } }
2.配置文件
<!-- 方式三:注解实现--> <bean id="annotationPoint" class="com.han.diy.AnnotationPoint"/> <!-- 开启注解支持 JDK(默认 proxy-target-class="false") cglib proxy-target-class="true"--> <aop:aspectj-autoproxy proxy-target-class="true"/>
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.2mybatis-spring
1,编写数据源配置
2,SQL Session Factory
3,SQL Session Template
4,需要给接口加实现类
5,将自己写的实现类注入到Spring中
6,测试使用即可
实现以下:
12.1回忆MyBatis
编写pojo实体类
package com.kuang.pojo; public class User { private int id; //id private String name; //姓名 private String pwd; //密码 } 1234567
实现mybatis的配置文件
<?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&useUnicode=true&characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <package name="com.kuang.dao"/> </mappers> </configuration> 1234567891011121314151617181920212223242526
UserDao接口编写
public interface UserMapper { public List<User> selectUser(); } 123
接口对应的Mapper映射文件
<?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> 1234567891011
测试类
@Test public void selectUser() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = newSqlSessionFactoryBuilder().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(); } 1234567891011121314151617
12.2.MyBatis-Spring学习
引入Spring之前需要了解mybatis-spring包中的一些重要类;
http://www.mybatis.org/spring/zh/index.html
 
在这里插入图片描述
什么是 MyBatis-Spring?
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。
知识基础
在开始使用 MyBatis-Spring 之前,你需要先熟悉 Spring 和 MyBatis 这两个框架和有关它们的术语。这很重要
MyBatis-Spring 需要以下版本:
MyBatis-Spring
MyBatis
Spring 框架
Spring Batch
Java
2.0
3.5+
5.0+
4.0+
Java 8+
1.3
3.4+
3.2.2+
2.1+
Java 6+
如果使用 Maven 作为构建工具,仅需要在 pom.xml 中加入以下代码即可:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> 12345
要和 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> 123
注意:SqlSessionFactory需要一个 DataSource(数据源)。这可以是任意的 DataSource,只需要和配置其它 Spring 数据库连接一样配置它就可以了。
13,声明式事务
1,回归事务
·把一组业务当成一个业务来做;要么都成功要么都失败
·事务在项目开发中,十分的重要,涉及到数据的一致问题,不能马虎!
·确保完整性和一致性;
事务ACID原则:
·原子性
·一致性
·隔离性
多个业务可能操作一个资源,防止数据损坏
·持久性
事务一旦提交,无论发生什么问题结果都不会在受影响,被持久化的写到存储器中!
2,Spring中的事务管理
·声明式事务:AOP
·编程式时务:需要在代码中,进行事物的管理
思考:
为什么需要事务?
·如果不配置事务,可能存在数据提交不一致的情况下;
·如果我们不在Spring中去配置声明式事务,我们就需要在代码中手动配置事务!
·事务在项目开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!
笔记摘抄自:
13.声明式事务
13.1.回顾事务
  • 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!
  • 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。
事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。
事务四个属性ACID
  1. 原子性(atomicity)
  • 事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
  1. 一致性(consistency)
  • 一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
  1. 隔离性(isolation)
  • 可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
  1. 持久性(durability)
  • 事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
测试
将上面的代码拷贝到一个新项目中
在之前的案例中,我们给userDao接口新增两个方法,删除和增加用户;
//添加一个用户 int addUser(User user); //根据id删除用户 int deleteUser(int id); 12345
mapper文件,我们故意把 deletes 写错,测试!
<insert id="addUser" parameterType="com.kuang.pojo.User"> insert into user (id,name,pwd) values (#{id},#{name},#{pwd}) </insert> <delete id="deleteUser" parameterType="int"> deletes from user where id = #{id} </delete> 1234567
编写接口的实现类,在实现类中,我们去操作一波
public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper { //增加一些操作 public List<User> selectUser() { User user = new User(4,"小明","123456"); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.addUser(user); mapper.deleteUser(4); return mapper.selectUser(); } //新增 public int addUser(User user) { UserMapper mapper = getSqlSession().getMapper(UserMapper.class); return mapper.addUser(user); } //删除 public int deleteUser(int id) { UserMapper mapper = getSqlSession().getMapper(UserMapper.class); return mapper.deleteUser(id); } } 1234567891011121314151617181920212223
测试
@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); } 1234567
报错:sql异常,delete写错了
结果 :插入成功!
没有进行事务的管理;我们想让他们都成功才成功,有一个失败,就都失败,我们就应该需要事务!
以前我们都需要自己手动管理事务,十分麻烦!
但是Spring给我们提供了事务管理,我们只需要配置即可;
13.2.Spring中的事务管理
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
编程式事务管理
  • 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
  • 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
  • 一般情况下比编程式事务好用。
  • 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
  • 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
使用Spring管理事务,注意头文件的约束导入 : tx
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> 1234
事务管理器
  • 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。
  • 就是 Spring的核心事务管理抽象,管理封装了一组独立于技术的方法。
JDBC事务
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> 123
配置好事务管理器后我们需要去配置事务的通知
<!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--配置哪些方法使用什么样的事务,配置事务的传播特性--> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <tx:method name="search*" propagation="REQUIRED"/> <tx:method name="get" read-only="true"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> 123456789101112
spring事务传播特性:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
  • propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
  • propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
  • propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
  • propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
  • propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
  • propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。
假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。
就好比,我们刚才的几个方法存在调用,所以会被放在一组事务当中!
配置AOP
导入aop的头文件!
<!--配置aop织入事务--> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config> 12345
进行测试
删掉刚才插入的数据,再次测试!
@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未完待续.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 

posted @ 2022-03-31 14:14  王肖寒  阅读(109)  评论(0)    收藏  举报