原先的 Spring 学习的时候的笔记 整理了一下 觉得还行 简单实用 共享一下
1 要点记录
2
3 spring Ioc
4 {
5
6
7 1 spring bean 在反射创建对象后 使用的是单例模式! 存在数据安全的问题
8 属性是被共享的!
9 如果该属性有数据,会引起线程安全的问题!
10 <bean id="helloWorid" class="cn.itcast.springTest.HelloWorid" scope="prototype" > </bean>
11 可以通过 XML 配置来设置 spring 默认是 单例的 scope="prototype" 就变成了 多例的了
12
13 2 <bean id="personService" class="com.myapp.core.beanscope.PersonService" scope="singleton" init-method="init" destroy-method="cleanUp">
14
15 nit-method 是设置 spring 在创建bean节点里面的 对象 时 初始化的时候 调用的方法
16 注: 在构造 或 静态 后面调用
17 destroy-method 是设置 bean 节点创建的对象 在销毁的时候 调用的方法
18 注: 如果是多例 的时候 spring 不负责销毁动作
19
20
21
22 3 spring 容器 (反射出的类对象) 的 三种初始化方法
23
24 3.1 默认的是 调用 无参的构造函数
25
26 3.2 factory-method=“” 需要创建类中的 方法 通过该方法的到返回的类型
27 实例:
28 public class HelloWorldFactory {
29 public static HelloWorld getInstance(){
30 return new HelloWorld();
31 }
32 }
33
34
35 4 spring 中 只要声明一个 bean 节点 运行的时候就会创建一个对象
36
37
38 5 spring 在启动的时候 spring 容器配制中的类 就已经创建完成了!
39
40 6 控制容器中的类创建时候
41 lazy-init 这个属性中设置
42 <bean id="helloWorid" class="cn.itcast.springTest.HelloWorid" lazy-init="true" ></bean>
43 在启动spring容器的时候,spring容器配置文件中的类就已经创建完成对象了
44 lazy-init
45 default false
46 true 在context.getBean的时候才要创建对象
47 * 优点
48 如果该bean中有大数据存在,则什么时候context.getBean,什么时候创建对象
49 可以防止数据过早的停留在内存中,做到了懒加载
50 * 缺点
51 如果spring配置文件中,该bean的配置有错误,那么在tomcat容器启动的时候,发现不了
52 false 在启动spring容器的时候创建对象
53 * 优点
54 如果在启动tomcat时要启动spring容器,
55 那么如果spring容器会错误,这个时候tomcat容器不会正常启动
56 * 缺点
57 如果存在大量的数据,会过早的停留在内存中
58 <bean id="helloWorld" class="cn.itcast.spring0909.createobject.when.HelloWorl" lazy-init="true"></bean>
59 <bean id="person" class="cn.itcast.spring0909.createobject.when.Perso" lazy-init="true"></bean>
60
61
62
63
64 总结:
65 spring的IOC :
66 1 IOC :spring容器控制对象的生命周期 ; 前提条件 :在容器中的bean 必须是单例
67 1.1 : 创建
68 1.1.1 : 方式
69 利用默认的构造函数
70 利用静态工厂方法
71 利用实例工厂方法
72 1.1.2 : 时机
73 lazy-init 为"default/false" 当启动 spring 容器的时候 创建bean
74 但是如果bean 是 prototype(多例) 时,特殊。这种情况无效
75
76 ps:在spring启动的时候就会发现错误 ,有肯能照成一些数据长时间的驻留在内存中
77
78 lazy-init 为"true" 当context。getBean时创建
79 bean为多例时,必须用这种方式创建对象
80
81 PS: 不能及时发现错误, 数据会在需要的时候加载
82
83 1.2 : 初始化
84 1.2.1 : 由spring容器调用init 方法, 在构造函数之后执行
85
86
87 1.3 : 销毁
88 1.3.1 : 如果是单利,则必须返回CalssPathXmlApplicationContext该容器,才能执行销毁
89 1.3.2 : 如果是多例,则容器不负责销毁
90
91 }
92
93 spring DI 依赖注入
94 {
95
96 定义: 给属性赋值就是依赖注入
97
98 1.1 利用Set来赋值
99 {
100 <bean id="person" class="cn.spring.di.xml.set.Person">
101 <!--
102 property就是代表属性
103 在spring中基本类型(包装类型和String)都可以用value来赋值
104 引用类型用ref赋值
105 -->
106 <property name="pid" value="5"></property>
107 <property name="pname" value="王二"></property>
108 <property name="student">
109 <ref bean="student"/>
110 </property>
111 <property name="lists">
112 <list>
113 <value>list1</value>
114 <value>list2</value>
115 <ref bean="student"/>
116 </list>
117 </property>
118 <property name="sets">
119 <set>
120 <value>set1</value>
121 <value>set2</value>
122 <ref bean="student"/>
123 </set>
124 </property>
125 <property name="map">
126 <map>
127 <entry key="map1">
128 <value>map1</value>
129 </entry>
130 <entry key="map2">
131 <value>map2</value>
132 </entry>
133 <entry key="map3">
134 <ref bean="student"/>
135 </entry>
136 </map>
137 </property>
138 <property name="properties">
139 <props>
140 <prop key="prop1">
141 prop1
142 </prop>
143 </props>
144 </property>
145 </bean>
146 }
147
148 1.2 利用构造函数赋值
149 {
150 <bean id="person" class="cn.spring.di.xml.constructor.Person">
151 <!--
152 构造函数的参数
153 index 第几个参数,下标从0开始
154 type 参数的类型
155 ref 如果类型是引用类型,赋值
156 value 如果类型是基本类型,赋值
157 说明:
158 只能指定一个构造函数
159 -->
160 <constructor-arg index="0" type="java.lang.String" value="露露"></constructor-arg>
161 <constructor-arg index="1" ref="student"></constructor-arg>
162 </bean>
163
164 <bean id="student" class="cn.spring.di.xml.constructor.Student"></bean>
165
166 类:
167 public Person(Long pid,String pname){
168 this.pid = pid;
169 this.pname = pname;
170 }
171
172 public Person(String pname,Student student){
173 this.pname = pname;
174 this.student = student;
175 }
176
177 }
178
179
180 }
181
182
183 IOC 和DI 做了什么事情?
184
185 * 创建对象
186 * 给对象赋值
187
188 IOC 和DI 的意思
189
190 * 可以在类中引用一个接口,而给接口赋值的工作交给spring容器来做,程序员只需要在配置文件中做一些配置就行。
191 这样在客户端做到了 完全的 面向接口编程
192
193
194
195
196 spring AOP :
197
198 {
199 * AOP 的核心就是动态代理;
200 其实就是 为目标类 方法进行一次包装 , 在方法执行前 和之后 触发其他模块方法执行
201
202 * springAOP的各个概念:
203
204 1. 切面:
205 切面指的就是 对目标类方法包装 时 提前或之后执行的方法的 类对象
206 2. 通知:
207 指得是 对目标类方法包装 时 提前或之后执行的方法
208 3. 切入点:
209 指的是 只有符合切入点,才能把通知和目标方法结合在一起 就是一个对目标方法的一个验证
210 4. 连接点:
211 指的是 客户端调用的方法 也就是具体调用的方法
212
213 * 代理对象的方法=通知+目标方法
214 * aop:做到了代码块的重用
215
216
217 关于SpringAOP的 配置 从spring_aop示例中找寻
218
219 关于切入点表达式 从 spring.xls 表格中找寻
220
221
222
223 springAOP 的原理:
224
225
226
227 * 加载配置文件,启动spring容器
228 * spring容器为bean创建对象
229 * 解析aop的配置,会解析切入点表达式
230 * 看纳入spring管理的那个类和切入点表达式匹配,如果匹配则会为该类创建代理对象
231 * 代理对象的方法体的形成就是目标方法+通知
232 * 客户端在context.getBean时,如果该bean有代理对象,则返回代理对象,如果没有代理对象则返回原来的对象
233
234
235 * 说明:
236 如果目标类实现了接口,则spring容器会采用jdk proxy, 如果目标类没有实现接口,则spring容器会采用 cglibproxy
237
238
239
240
241 PS: 有参数的通知方法:
242
243 通知有 前置 后置 异常 最终 环绕 这些类型
244
245 通长自己写的通知方法是用的是 无参方法, 如果需要获得 连接点 也就是客户端调用方法 的信息的时候 使用有惨方法
246
247 示例:
248 {
249
250 /**
251 * 前置通知
252 * 通过JoinPoint获取连接点的信息
253 */
254 public void beginTransaction(JoinPoint joinPoint){
255 joinPoint.getArgs();//获取方法的参数
256 String methodName = joinPoint.getSignature().getName();
257 System.out.println(methodName);
258 System.out.println("begin transaction");
259 }
260 /**
261 * 后置通知 ,Object val 是返回值
262 * 注意 在配置文件中 配置的后置通知XML 中 returning=”var“
263 * 那么 定义方式的时候 返回值名称也得 和 配置文件中相同
264 *
265 * 如果目标方法遇到异常 ,改通知将不执行
266 *
267 */
268 public void commit(JoinPoint joinPoint,Object val){
269 List<Person> personList = (List<Person>)val;
270 System.out.println(personList.size());
271 System.out.println("commit");
272 }
273 /**
274 * 最终通知 // 在目标方法执行之后
275 * 无论目标方法是否遇到异常 ,都执行 经常做一些关闭资源的动作
276 */
277 public void finallyMethod(){
278 System.out.println("finally method");
279 }
280
281 /**
282 * 异常通知
283 */
284 public void exceptionMethod(Throwable ex){
285 System.out.println(ex.getMessage());
286 }
287 /**
288 * 环绕通知
289 * 能控制目标方法的执行 相当于拦截器方法
290 * @param joinPoint = 客户端调用的方法
291 * @throws Throwable
292 */
293 public void aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{
294 System.out.println("aaaa");
295 // 获取客户端调用方法的名称
296 String methodName = joinPoint.getSignature().getName();
297 // 判断是否是 期望的方法
298 if("savePerson".equals(methodName)){
299 // 是 就让 客户端调用的方法执行
300 joinPoint.proceed();//
301 }
302 // 否 客户端方法 不执行
303 }
304
305
306 }
307
308 PS: 前置通知 和 后置通知 只能在目标方法中 添加内容 ,但是控制不了方法的指向
309
310 重要提示: 通知是通过 配置文件的从上往下 执行的!
311 }
312
313
314
315
316
317 spring 中的 注解器 使用和运行机制
318
319
320 PS: @Resource 这个注解类 是最常用的
321
322
323
324 依赖注入的注解解析器
325
326 {
327 原理
328
329 * 启动spring容器,并且加载配置文件
330 * 会为student和person两个类创建对象
331 * 当解析到<context:annotation-config></context:annotation-config>
332 会启动依赖注入的注解解析器
333 * 会在纳入spring管理的bean的范围内查找看哪些bean的属性上有@Resource注解
334 * 如果@Resource注解的name属性的值为"",则会把注解所在的属性的名称和spring容器中bean的id进行匹配
335 如果匹配成功,则把id对应的对象赋值给该属性,如果匹配不成功,则按照类型进行匹配,如果再匹配不成功,则报错
336 * 如果@Resource注解的name属性的值不为"", 会把name属性的值和spring容器中bean的id做匹配,如果匹配
337 成功,则赋值,如果匹配不成功 ,则直接报错
338 * 说明:
339 * 注解只能用于引用类型
340 * @author Administrator
341 *
342
343
344 实例:
345 {
346
347 <!--
348 1、导入命名空间
349 xmlns:context="http://www.springframework.org/schema/context"
350 http://www.springframework.org/schema/context
351 http://www.springframework.org/schema/context/spring-context-2.5.xsd
352 2、导入依赖注入的注解解析器
353 <context:annotation-config></context:annotation-config>
354 3、把student和person导入进来
355 -->
356 <context:annotation-config></context:annotation-config>
357 <bean id="student" class="cn.spring.di.annotation.Student"></bean>
358 <bean id="person" class="cn.spring.di.annotation.Person"></bean>
359
360
361
362 public class Person {
363 @Resource(name="student")
364 //@Autowired//按照类型进行匹配
365 //@Qualifier("student")
366 private Student studen;
367
368 }
369 public class Student {
370 public void say(){
371 System.out.println("student");
372 }
373 }
374
375 }
376 }
377
378 类扫描的注解解析器
379 {
380
381 原理
382 * 启动spring容器,加载配置文件
383 * spring容器解析到
384 <context:component-scan base-package="cn.spring.scan"></context:component-scan>
385 * * spring容器会在指定的包及子包中查找类上是否有@Component
386 * * 如果@Component注解没有写任何属性
387 * @Component
388 * public class Person{
389 *
390 * }
391 * ==
392 * <bean id="person" class="..Person">
393 * 如果@Component("aa")
394 * @Component
395 * public class Person{
396 *
397 * }
398 * ==
399 * <bean id="aa" class="..Person">
400 * * 在纳入spring管理的bean的范围内查找@Resource注解
401 * * 执行@Resource注解的过程
402 * 说明:
403 * xml效率比较高,但是书写比较麻烦
404 * 注解效率比较低,书写比较简单
405 * 不推荐实用 类扫描注解解析器 Spring Ioc 的目的就是解耦 如果控制 还在代码中写死 这种意义就不大 同时也不方便 阅读代码
406 *
407
408 实例
409 {
410 <!--
411 1、导入命名空间
412 xmlns:context="http://www.springframework.org/schema/context"
413 http://www.springframework.org/schema/context
414 http://www.springframework.org/schema/context/spring-context-2.5.xsd
415 2、启动类扫描的注解解析器
416 3、启动依赖注入的注解解析器
417 -->
418
419 <!--
420 component就是bean
421 base-package
422 会在base-package的值所在的包及子包下扫描所有的类
423 -->
424 <context:component-scan base-package="cn.spring.scan"></context:component-scan>
425
426
427
428 @Component("perso")
429 public class Person {}
430 @Component
431 public class Student {}
432
433
434
435
436 }
437
438
439
440
441
442
443 }
444
445 使用构造器 来控制 bean 加载的 初始化 和 销毁 方法,
446
447 实例:
448 {
449
450 @PostConstruct // 类构造器之后调用
451 public void init(){
452 System.out.println("init");
453 }
454
455 @PreDestroy // 在销毁动作之前调用
456 public void destroy(){
457 System.out.println("destroy");
458 }
459
460 }
461
462
463 PS: 如果一个类中有 基本类型 ,并且 基本类型是spring的形式来赋值。 这个时候必须使用XML来赋值,不能使用注解 赋值
464
465 PS: 不推荐使用 类型匹配 也就是
466 {
467 @Resource
468 private Student studenA;
469 这里找的是 bean 的 class 的值
470
471 如果定义多个bean class 的值 相同 那么就会报错 因为不确定是哪一个 bean
472
473
474
475 }
476
477
478
479 spring容器中的继承问题
480
481 1.1.1 默认情况下 即便给是 父类的属性注入了 对应的值 ,但是子类 并不会 的到父类的值
482
483 解决方法:
484
485 parent : 让子类拥有父类属性的值
486
487 <bean id="person" class="cn.springTest.Person" parent="personBase"></bean>
488
489 同样 可以让子类拥有父类的属性 自己赋值 不用写 parent 属性
490 <bean id="student" class="cn.spring.extend.Student">
491 <property name="name" value="aaaaa"></property>
492 </bean>
493
494
495
496 abstract
497 spring容器不会为该类创建对象
498
499 <bean id="person" class="cn.spring.extend.Person" abstract="true">
500 <property name="name" value="王二的哥"></property>
501 </bean>
502
503
504
505 Spring 事物问题:
506
507
508 {
509 * 详情请看 JDBC / transaction 文件下的示例
510
511 * 关键点
512
513 <!-- 声明事务通知 id事务标识 transaction-manager -->
514 <!-- 事务管理器 -->
515 <bean id="transactionManager"
516 class="org.springframework.jdbc.datasource.
517 DataSourceTransactionManager">
518 <property name="dataSource">
519 <ref bean="dataSource"/>
520 </property>
521 </bean>
522
523 Ps : id="transactionManager" 的Class 是 一个继承了一个抽象父类的 子类 目的是为了多态,由子类告诉Spring 使用数据库是那种技术
524
525
526 <!-- 声明目标方法中哪些方法需要事务,哪些不需要事务 -->
527 <tx:advice id="tx" transaction-manager="transactionManager">
528 <tx:attributes>
529 <!-- name 限定方法的名称 isolation 隔离机制 propagation 传播机制 ready-only 只读 -->
530 <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED"
531 read-only="false" />
532 </tx:attributes>
533 </tx:advice>
534
535
536 PS: propagation 传播机制 基本用的都是默认的 REQUIRED 指得是 一个方法中如果有多个事物方法 ,那么就把第一个事物方法后面的事物方法逐个附加到第一个事物方法中。 启动一次事物就行!
537
538
539 <!-- spring容器做的事情 -->
540 <aop:config>
541 <aop:pointcut
542 expression="execution(* cn.spring.jdbc.transaction.
543 PersonServiceImpl.*(..))"
544 id="perform" />
545
546 Ps: 声明一个切面 的 触发点
547
548 <aop:advisor advice-ref="tx" pointcut-ref="perform"/>
549
550 Ps: 不需要自己声明切面类, 直接 创建切面 通知 指定到 事物方法
551 </aop:config>
552 Ps: 不经常写可能会 忘记怎么写 我的方式是 从下上往上写 先写 <aop:config> --> <tx:advice>--><bean>
553 }
554
555
556
557
558
559 Spring dataSource 定义数据库连接类的两种方式
560
561 *
562
563 <!-- 产生dataSource -->
564 <bean
565 class="org.springframework.beans.factory.
566 config.PropertyPlaceholderConfigurer">
567 <property name="locations">
568 <value>classpath:jdbc.properties</value>
569 </property>
570 </bean>
571 <bean id="dataSource" destroy-method="close"
572 class="org.apache.commons.dbcp.BasicDataSource">
573 <property name="driverClassName" value="${jdbc.driverClassName}" />
574 <property name="url" value="${jdbc.url}" />
575 <property name="username" value="${jdbc.username}" />
576 <property name="password" value="${jdbc.password}" />
577 </bean>
578
579 PS: 读取 classpath:jdbc.properties 这个路径中 的 properties 配置文件中相同,将配置文件中对应的值赋
580
581 * properties 配置文件中的数据
582 jdbc.driverClassName=com.mysql.jdbc.Driver
583 jdbc.url=jdbc\:mysql\://localhost\:3306/hibernate
584 jdbc.username=root
585 jdbc.password=root
586
587
588
589
590
591 *
592
593 <!-- 配置dbcp的数据库连接池 -->
594 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
595 <property name="driverClassName" value="com.mysql.jdbc.Driver" />
596 <property name="url" value="jdbc:mysql://localhost:3306/hibernate" />
597 <property name="username" value="root" />
598 <property name="password" value="root" />
599 </bean>
600
601
602
603
604
605 经验:
606
607 使用 AOP后 测试的时候 首先第一个先检查 获取的对象是否是个代理对象
608
609
610 配置Spring 文件的时候 思路
611 程序员 做什么
612 spring 做什么
613
614
615
616 关于 切面点 需要适用于 多个 包 的问题
617
618 expression="execution(* cn.spring.*.transaction.PersonServiceImpl.*(..))"
619 id="perform" />
620
621 适用通配符 * 来模糊匹配 结节这个问题
622
623
624
625
626
627