概述
Spring FrameWork 特点
- 非侵入式
- 控制反转
- 面向切面编程
- 容器化管理
- 组件化
- 一站式
IOC 控制反转
概述
Inversion of Control
- 用容器管理所有 Java 对象的实例化和初始化,控制依赖关系,称为 SpringBean
-
xml 配置文件
-
抽象 BeanDefinitionReader 读取
-
装配,读取信息,利用反射实例化
- BeanFactory、ApplicationContex
-
用 Context.getBean("...") 来获取
基于 xml 管理
获取 Bean
xml 定义
1
|
<bean id="helloworldone" class="ccom.atguigu.spring6.bean.He11owor1d"></bean>
|
Context.getBean("...") 获取
1
2
|
//根据类型获取接口对应bean
UserDaouserDao= context.getBean(UserDao.class);
|
依赖注入
- set 注入
- 构造器注入
<constructor-arggname="bnamevalue="java开发"></constructor-arg>
是不是只能注入默认值?
-
特殊值注入
- 对象中注入其他对象(表示关系)
- 法一:引入外部/内部类,bean 标签中嵌套
ref
- 法二:级联赋值,直接嵌套对所注入的对象的属性的赋值
-
数组类型注入
-
List 集合属性注入
-
map 集合属性注入
-
引用集合类型(?util 整合)
-
p 命名空间注入
引入外部属性
创建外部属性文件 .property
xml 中配置读取即可
作用域
配置 scope 来指定作用域
- singleton 单例
- prototype 多例,每次获取时创建
生命周期

FactoryBean 机制
根据接口实现 FactoryBean,自定义 getObjet()方法返回值,来控制产生的对象
基于注解注解管理
- 开启组件扫描
1
2
|
<!--开启组件扫描功能-->
<context:component-scanbase-package="com.atguigu.spring6"></context:component-scan>
|
- 注解说明

@Autowired 注入
- set 方法注入
1
2
3
4
|
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
|
-
构造方法注入
-
形参上注入
-
根据名称进行注入(而非接口名)
@Resource 注入
默认根据 name 标签进行注入
全注解开发
无需使用配置文件,写一个配置类替代配置文件
1
2
3
4
5
|
@configuration
//@componentscan({"com.atguigu.spring6.controller"
//"com.atguigu.spring6.service","com.atguigu.spring6.dao"})
@componentscan("com.atguigu.spring6")
public class Spring6config {}
|
手写 IoC
反射
获取对象:
1
2
3
4
5
6
7
8
9
10
|
public void test01(){
//1 类名.cLass
Class clazz1 = Car.class;
//2 对象.getCLass()
Class clazz2 =newv Car().getclass();
//3 CLass.forName("全路径")
Class clazz3 = Class.forName( className: "......");
//实例化
Object o = clazz3.getDeclaredConstructor().newInstance();
}
|
获取方法:
1
2
3
4
5
6
7
8
|
public void test02() throws Exception {
Classclazz = Car.class;
1/获取所有构造
Constructor[]] constructors = clazz.getconstructors();
for (Constructor c:constructors) {......}
// 方法名:c.getname() 参数个数(public):c.getConstructor()
// 参数个数(所有):c.getDeclaredConstructor()
}
|
构造对象:
1
2
3
|
Constructorc2=(clazz.getDeclaredConstructor(......)
c2.setAccessible(true);
Car car2 = (Car)c2.newInstance( ..initargs: "捷达", 15,“白色");
|
获取属性:
1
2
3
4
5
6
7
8
|
Classclazz = Car.class;
//获取所有pubLic属性
Field[] fields = clazz.getFields();
//获取所有属性(包含私有属性)
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields){
System.out.println(field.getName());
}
|
操作方法
1
2
3
4
5
6
7
8
|
private方法
Method[] methodsAll = clazz.getDeclaredMethods();
for (Method m:methodsAll) {
//执行方法 runI
if(m.getName().equals("run")) {
m.setAccessible(true);
m.invoke(car) ;
}
|
实现
步骤
配置
@Bean
1
2
3
4
|
@Target(ElementType.TYPE) // 目标
@Retention(RetentionPolicy.RUNTIME) // 运行范围
public @interface Bean
}
|
@Di
ApplicationCotext 接口
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
26
27
28
29
30
31
32
33
34
35
36
37
|
//创建有参数构造,传递包路径,设置包扫描规则
//扫描当前包及其子包,哪个类有@Bean注解,把这个类通过反射实例化
public AnnotationApplicationContext implement ApplicationContext(String basePackage) {
// 路径转义,点替换为斜杠
String packagePath = basePackage.replaceAll("\\.","\\\\")
// 获取绝对路径
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader()·getResources(packagePath);
while(urls.hasMoreElements()) {
URL url = urls.nextElement();
String filePath= URLDecoder.decode(url.getFile(), "utf-8");
loadBean(new File(filePath)); // 实现 loadBean 方法
}
loadDi(); // 实现 loadDi 方法
}
public static void loadBean(File file){
// 1.判断当前内容是否是文件夹
// 2.是,则获取当前文件夹所有内容
// 3.文件夹为空,返回空
// 4.文件夹不为空,遍历文件夹所有内容
// 4.1.遍历每个File对象,继续判断,如果还是文件,递归
// 4.2.不是文件夹,是文件
// 4.3.得到包文件 + 类名称部分
// 4.4.判断当前文件类型是否.cLass
// 4.5.如果是.cLass类型,把路径\替换成。把.cLass去掉
// 4.6.判断类上面是否有注解@Bean,如果有实例化过程
// 4.7.把对象实例化之后,放到map集合bearFactory
}
private void loadDi() {
//实例化对象在beanFactory的map集合里面
//1遍历beanFactory的map集合
//2获取map集合每个对象(vaLue),每个对象属性获取到
//3遍历得到每个对象属性数组,得到每个属性
//4判断属性上面是否有@Di注解
//5如果有@Di注解,把对象进行设置(注入)
}
|
AOP 面向切面
引入
问题:
代理模式:
优化:
AOP:通过预编译和动态代理,在不修改程序源码情况下,给程序添加功能
-
抽取横切关注点
-
整合横切关注点为通知方法
-
将各种通知方法整合为切面类
基于注解实现
分类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Aspect//切阻尖
@Component //ioc容器
public class LogAspect {
//设置切入点和通知类型
//通知类型:
//前置 @Before(value = "切入点表达式")
public void beforeMethod(JoinPoint joinPoint) {
StringmethodName = joinPoint.getSignature().getName();
Object[] args = jqinPoint.getArgs();
// 获取连接点的信息
}
//返回 @AfterReturning
//异常 @AfterThrowing
//后置 @After()
//环绕 @Around()
}
|
@Order 控制切面优先级
基于 xml 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<context:component-scanbase-package="com.atguigu.aop.xml"></context:component-scan>
<aop:config>
<!--配置切面类-->
<aop:aspect ref="loggerAspect">
<aop:pointcut id="pointcut"
expression="execution(*com.atguigu.aop.xml.calculatorImpl.*(..))"/>
<aop:before method="beforeMethod"pointcut-ref="pointcut"></aop:before>
<aop:after method="afterMethod"pointcut-ref="pointcut"></aop:after>
<aop:after-returning method="afterReturningMethod"returning="result"pointcut-
ref="pointcut"></aop:after-returning>
<aop:after-throwing method="afterThrowingMethod"throwing="ex"pointcut-
ref="pointcut"></aop:after-throwing>
<aop:around method="aroundMethod"pointcut-ref="pointcut"></aop:around>
</aop:aspect>
</aop:config>
|
事务
JDBC Template
增:
1
2
3
4
5
6
7
|
//1添加操作
//第一步编写sqL语句
String Sql = "INSERT INTO t_emp VALUES(NULL,?,?,?)";I
//第二步调用jdbcTempLate的方法,传入相关参数
//Object[] params ={"东方不败",20,"未知"};
//int rows = jdbcTemplate.update(sql,params);
int rows = jdbcTemplate.update(sql, ..args:"东方不败",20,"未知");
|
改:
1
2
3
|
//2修改操作
String sql ="update t_emp set name=? where id=?";
int rows =jdbcTemplate.update(sql, ..args: "林平之atguigu",3);
|
删:
1
2
3
|
//3删除操作
String sql'deletefromt_empwhere id=?";
introws=jdbcTemplate.update(sql, ..args: 3);
|
查:
1
2
3
4
5
|
public void testSelectObject() {
String sql="select*from t_emp
List<Emp>list = jdbcTemplate.query(sql,
new BeanPropertyRowMapper<>(Emp.class));
}
|
基于注解的声明式事务
保证事务的一致性、隔离性、持久性、原子性
Transactional 标签声明事务,可以设置:
- 只读
- 超时
- 回滚策略,哪些异常不回滚
- 隔离级别
- 传播行为,事务方法之间调用的处理逻辑
全注解
不用 XML,改用配置类