Spring
1 、Spring
1.1 简介
Spring理念:使现有的技术更加容易使用,本身是个大杂烩,整合了现有的技术框架
SSH ->Stucts2+Spring+Hibernate || SSM->SpringMVC+Spring+Mybatis
下载方式:
下载地址:repo.spring.io
github:GitHub - spring-projects/spring-framework: Spring Framework
Maven的依赖导入:
`
org.springframework spring-webmvc 5.3.21
1.2 优点
spring是一个开源的免费的框架(容器)
Spring是一个轻量级的非入侵式的框架
控制反转(IOC) 面向切面编程(AOP)
支持事务的处理,对框架整合的支持
总结:Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.3 组成
1.4扩展
现代化的Java开发
构建一切-(SpringBoot)–>协调一切(Spring Cloud)—>连接一切(Spring Cloud Data Folw)
- Spring Boot
- 快速开发的脚手架
- 基于SpringBoot可以快速的 开发单个微服务
- 约定大于配置
- SpringCloud
- SpringCloud式基于SpringBoot实现的
因为大多数的公司使用SpringBoot快速开发,学习SpringBoot的前提就是学习Spring和SpringMVC
弊端:发展了太久之后,违背了原来的理念,配置十分繁琐,“配置地狱”
2、IOC的推导
UserDao接口
UserDaoImpl接口的实现类
UserService业务接口
UserServiceImpl业务实现类
在之前的业务中用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码,如果程序代码量十分庞大修改一次的成本代价十分昂贵
我们去用一个Set接口来实现
1
2
3
4
5private UserDao userDao;
//利用Set进行动态实现值的注入!
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}- 之前,程序是主动创建对象!控制权在程序员手中
- 使用了Set注入后,程序不再具有主动性,而是变成被动的接收对象
这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建了,系统的耦合性大大降低,可以更加专注的在业务实现上
3、HelloSpring
4、IOC创建对象的方式、
使用无参构造创建对象(默认)
假设要使用有参构造方法
- 下标赋值
<constructor-arg index="下表数" value="下标值"/>
- 通过类型创建(不推荐):
<constructor-arg type="java.lang.String" value="张锋学JAVA"/>
- 直接通过参数名来设置:
1
2
3<bean id="User" class="com.zhang.pojo.User">
<constructor-arg name="name" value="张锋学JAVA"/>
</bean>- 下标赋值
总结:在配置文件加载的时候,容器中的管理对象就已经开始初始化了
5、Spring配置
别名
1
2<!--如果添加了别名可以用别名来获取对象-->
<alias name="User" alias="userasd"/>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>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、依赖注入
构造器注入
前面说过了
Set方式注入
【环境搭建】
1.复杂环境
1
2
3
4
5
6
7
8
9
10
11
12
13package 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
9public 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
<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
7public 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
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 | <!--List注入--> |
4.set注入
1 | <property name="games"> |
5 空值注入
1 | <property name="wife"> |
6 properties注入
1 | <!--properties注入--> |
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的自动装配
环境搭建:一个人有两个宠物
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
5private String name;
//如果Autowired后面的required属性为false,说明这个对象可以null,否则不允许为空
private cat cat;
private dog dog;如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualfier(value=”xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入
测试代码:
1
2
3
4
5
6
7private String name;
private cat cat;
private dog dog;
7、Spring注解开发
1.自动装配配置
@autowired :通过类型和名字进行自动装配,如果autowired不能唯一自动装配上属性,则需要通过@Qualifier(value=”xxx”)
@Nullable:字段标记了这个注解,说明这个字段可以是Null
@Resource 通过名字类型自动装配
@Component:组件,放在类上,说明这个类被Spring管理了,就是bean
2.属性如何注入
1 | //组件 |
3.衍生注解
@Component有几个衍生注解,我们在Web开发中,会按照MVC三层架构进行分层
- dao [@Repository ]
- service[@Sercive]
- controller[ ]
4.作用域
1 | //组件 |
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
24import 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 );
}
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 | public class Client { |
3、AOP(面向切面编程)
使用Spring实现AOP
xml中配置文件头:
1
2
3
4
5
6
7
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:原生的Spring API接口
以创建日志为例: 两个日志类为:Log和AfterLog
1
2
3
4
5
6
7
8
9
10
11package com.zhang.demo1;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class log implements MethodBeforeAdvice {
//method要执行的目标的对象方法
//Object:参数
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
14package com.zhang.demo1;
import org.springframework.aop.AfterAdvice;
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("执行了"+method.getName()+"结果为"+returnValue);
}
}
ApplicationContext.xml
1 |
|
测试类:
1 | import com.zhang.demo1.UserService; |
输出结果
第二种方法:自定义切点法
自定义切点类 DiyPointCut
1 | package com.zhang.demo1; |
配置文件:ApplicationContext.xml
1 |
|
输出结果:
AOP原理如图:
9、Mybatis-Spring
项目结构
编写数据源配置
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&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>sqlSessionFactory
1 | <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> |
- sqlSessionTemplate
1 | <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> |
- 需要给接口加实现类
1 | public class UserMapperImp implements UserMapper{ |
10、声明式事务
1、回顾事务
- 把一组业务当成一个业务来做,要么都成功,要么都失败!
- 十五在项目开发中十分重要,设一道数据一致性的问题,不能马虎
- 确保完整性和一致性
事务的ACID原则:
- 原子性
- 一致性
- 隔离性
多个业务放到同一个资源防止数据破坏
- 持久性
事务一旦提交,无论发生什么问题,结果都不会在被影响,被持久化写道存储器中