spring版本为5.3.5 文章的发表时间为2021.7请注意文章的时效性!!!
春天------>给软件行业带来了春天!
2002,interface 21,Spring框架的雏形
Spring框架即以interface21框架为基础,经过重新设计;并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
Rod Johnson 悉尼大学的音乐,计算机双学位
Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架。
i18n(其来源是英文单词 internationalization的首末字符i和n,18为中间的字符数)是“国际化”的简称。
SSH:Struct2 + Spring +Hibernate
SSM:SpringMVC + Spring +Mybatis
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.5version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.5version>
dependency>
总结一句话::Spring就是一个轻量级的控制反转(IOC)和面向切面编程的框架!
Spring Boot
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,修改一次的成本价十分昂贵!
我们使用一个set接口实现
private UserDao userDao ;
//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
这种思想,从本质上解决了问题,我们程序员不用自己去管理对象了。系统的耦合性大大降低,可以更加专注的在业务的实现上。这是IOC的原型!
IOC本质
控制反转lOC(Inversion of Control)。是一种设计思想,**DI(依赖注入)**是实现lOC的一种方法,也有人认为DI只是lOC的另一种说法。没有lOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
loC是Spring框架的核心内容,使用多种方式完美的实现了loC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现loC。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从loc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为—体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是loC容器,其实现方法是依赖注入(Dependency Injection,Dl)。
<bean id="hello" class="com.utaha.pojo.Hello">
<property name="name" value="Spring"/>
bean>
这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的。
反转:程序本身不创建对象,而变成被动的接收对象。
依赖注入:就是利用set方法来进行注入的。
IOC是一种编程思想,由主动的编程变成被动的接收。
可以通过new ClassPathXmIApplicationContext去浏览一下底层源码。
OK,到了现在,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改。
所谓的loC,一句话搞定:对象由Spring来创建,管理,装配!
<!--
ref 引用spring容器中已经创建好的对象 (引用类型)
value 具体类型的值 (基本类型)
-->
1.使用无参构造创建对象,默认!
2.假设我们要使用有参构造创建对象。
<bean id="user" class="com.utaha.pojo.User">
<property name="name" value="zhangsan"/>
bean>
<bean id="user" class="com.utaha.pojo.User">
<constructor-arg index="0" value="lisi"/>
bean>
<bean id="user" class="com.utaha.pojo.User">
<constructor-arg type="java.lang.String" value="wangwu"/>
bean>
<bean id="user" class="com.utaha.pojo.User">
<constructor-arg name="name" value="zhaoliu"/>
bean>
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!
<alias name="user" alias="utaha" />
<bean id="userT" class="com.utaha.pojo.UserT" name="userT2,u2 u3;u4"/>
一般用于团队开发,可以使得多个配置文件导入合并为一个。
假设项目中有多个人开发,负责不同的类,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个,使用的时候使用总的就可以了。
<import resource="beans.xml" />
<bean id="user" class="com.utaha.pojo.User">
<property name="name" value="zhangsan"/>
bean>-->
<bean id="user" class="com.utaha.pojo.User">
<constructor-arg index="0" value="lisi"/>
bean>-->
<bean id="user" class="com.utaha.pojo.User">
<constructor-arg type="java.lang.String" value="wangwu"/>
bean>-->
<bean id="user" class="com.utaha.pojo.User">
<constructor-arg name="name" value="zhaoliu"/>
bean>
依赖 bean对象的创建依赖容器
注入 bean对象中的所有属性,由容器来注入
<bean id="address" class="com.utaha.pojo.Address">
<property name="address" value="寿阳"/>
bean>
<bean id="student" class="com.utaha.pojo.Student">
<property name="name" value="霞诗子"/>
<property name="address" ref="address"/>
<property name="books">
<array>
<value>D.A.Lvalue>
<value>overlordvalue>
<value>DXDvalue>
array>
property>
<property name="hobbies">
<list>
<value>Avalue>
<value>Cvalue>
<value>Gvalue>
<value>Nvalue>
list>
property>
<property name="card">
<map>
<entry key="IDCard" value="123456"/>
<entry key="Bank" value="45678"/>
map>
property>
<property name="games">
<set>
<value>Dotavalue>
<value>Azurlanevalue>
<value>fgovalue>
<value>WOWvalue>
set>
property>
<property name="wife">
<null/>
property>
<property name="info">
<props>
<prop key="学号">20210426prop>
<prop key="性别">boyprop>
<prop key="班级">2.2prop>
props>
property>
bean>
c命名空间,p命名空间
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
<bean id="user" class="com.utaha.pojo.User" p:name="utaha" p:age="17"/>
<bean id="user2" class="com.utaha.pojo.User" c:age="17" c:name="utaha"/>
注意点:
P命名空间和C命名空间不能直接使用,需要导入XML约束。
<bean id="user" class="com.utaha.pojo.User" p:name="utaha" p:age="17" scope="singleton"/>
原型模式
<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>
其余的在web开发才会使用
在Spring中有3种自动装配的方式:
环境搭建
一个人有两个宠物!
byName
<bean id="people" class="com.utaha.pojo.People" autowire="byName">
<property name="name" value="霞诗子"/>
bean>
byType
<bean id="people" class="com.utaha.pojo.People" autowire="byType">
<property name="name" value="霞诗子"/>
bean>
jdk1.5 spring2.5支持注解
要使用注解需要:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
beans>
@Autowired
直接在属性上使用(可以去掉set方法,直接依靠反射)
(也可以在set方法上)
@Nullable
@Nullable 字段标记了这个注解,说明这个字段可以为null
@Autowired由spring提供,byType、byName都找一遍
@Qualifier
@Qualifier可以通过byName注入
//(required = false)为空也不会报错
@Autowired(required = false)
@Qualifier(value = “cat222”)
如果@Autowired自动装配的环境比较复杂时候,自动装配无法通过一个【@Autowired】完成时候,我们可以使用@Qualifier(value=" xxx")去配合@Autowried共同使用,指定唯一的一个bean对象注入。
@Resource
@Resource(name=“xxx”)
@Resource和@Autowired的区别
@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。
如果查询的结果不止一个,那么@Autowired会根据名称来查找。
如果我们想使用按名称装配,也可以结合@Qualifier注解一起使用。
@Resource有两个中重要的属性:name和type。name属性指定byName,
如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,
当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
需要注意的是,@Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时,
@Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
@Resource装配顺序
最后推荐使用@Resource注解在字段上,这样就不用写setter方法了。
并且这个注解是属于J2EE的,减少了与Spring的耦合,这样代码看起就比较优雅 。
使用注解需要导入context约束,增加注解的支持。
/*
Component:组件
等价与
*/
@Component
public class User {
/*
等价于
也可以放在set方法上
*/
@Value("霞诗子")
public String name;
}
@Component的衍生 在web开发中,使用mvc三层架构分层
这四个注解功能都是一样的,都是代表某个类注册到Spring容器中,装配Bean。
@Autowired 自动装配 先type后name
@Qualifier(value="xxx")按name装配
@Nullable 字段标记了这个注解,说明这个字段可以为null
@Resource(name="xxx") 自动装配 先name后type
@Scope(“singleton”,“prototype”,“request”,“session”).
XML与注解
最佳实现
完全不使用xml配置文件。
javaConfig
java配置类等价于XML
//被@Configuration标记的类,也会被容器托管,注册到容器当中,因为他本身也就是一个@Component
@Configuration
//扫描包
@ComponentScan("com.utaha.pojo")
@Bean默认是单例模式,并且没有提供指定作用域的属性,可以通过
@Scope来实现该功能。
/*
=
注册一个bean,就相当于之前写的一个bean标签
方法名,就相当于bean标签中的id属性
方法返回值,相当于class属性
value
name
name 和 value 两个属性是相同的含义的, 在代码中定义了别名。
autowire
装配方式 有三个选项
Autowire.NO (默认设置)
Autowire.BY_NAME
Autowire.BY_TYPE
指定 bean 的装配方式, 根据名称 和 根据类型 装配, 一般不设置,采用默认即可
*/
@Bean(name = "user2")
这种纯java的配置方式,在springboot中随处可见。
代理模式分类
角色分析:
代码步骤:
代理模式的好处:
缺点:
一个真实角色就会产生一个代理角色;代码量会翻倍。开发效率会变低
需要了解两个类,Proxy、Invocationhandler(调用处理工具)
动态代理的好处:
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
提供声明式事务;分许用户自定义切面
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
切面(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
目标(Target):被通知对象。
代理(Proxy):向目标对象应用通知之后创建的对象。
切入点(PointCut):切面通知执行的“地点"的定义。
连接点(JointPoint) :与切入点匹配的执行点。
【重点】导入AOP织入包
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.5version>
dependency>
方式一:使用Spring的API接口【主要是SpringAPI接口实现】
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.utaha.service.impl.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut" />
aop:config>
方式二:自定义类来实现AOP【主要是切面定义】
<bean id="diy" class="com.utaha.diy.DiyPointCut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="pointcut" expression="execution(* com.utaha.service.impl.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
aop:aspect>
aop:config>
方式三:使用注解实现AOP
<context:annotation-config/>
<context:component-scan base-package="com.utaha"/>
<aop:aspectj-autoproxy proxy-target-class="false"/>
@Component
@Aspect
public class AnnotationPointCut {
//配置PointCut
@Pointcut("execution(* com.utaha.service.impl.UserServiceImpl.*(..))")
public void pointCut() {}
@Before(value = "pointCut()")
public void before() {
System.out.println("注解实现*********前********");
}
@After(value = "pointCut()")
public void after() {
System.out.println("注解实现*********后********");
}
@Around(value = "pointCut()")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
jp.proceed();//执行方法
Signature signature = jp.getSignature();//获得签名
System.out.println("signature:" + signature);
System.out.println("环绕后");
}
}
AOP有两个概念(切面,通知) OOP有两个概念(target,proxy) 连接的桥梁为(切入点和连接点)
步骤:
1.导入相关jar包
junit
mybatis
mysql
spring
aop织入
mybatis-spring
2.编写配置文件
3.测试
<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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/estore?characterEncoding=utf-8&serverTimezone=UTC&useSSL=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
bean>
<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/utaha/mapper/*.xml"/>
bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
beans>
是有4层,Impl中想要调用sqlSessionTemplate方法去实现增删改查,MapperImpl 注入bean中 ----->需要ref(sqlSessionTemplate)------->注入sqlSessionTemplate后仍需要ref(sqlSessionFactory)---------->注入sqlSessionFactory同理需要ref(dataSource)--------->注入dataSource
方式二 简化一步 不需要 sqlSessionTemplate
继承SqlSessionDaoSupport 父类 少注入一步,其他同理
事务的ACID原则:
原子性
一致性
隔离性
多个业务可能操作同一个资源,防止数据损坏
持久性
事务一旦提交,五轮系统发生什么问题,结果都不会被再影响,被持久化的写到存储器中
为什么需要事务?