Spring 实战4学习笔记(转)
http://blog.csdn.net/21aspnet/article/details/51386557
1.IOC装配Bean
参考【spring实战4 2.2】,作者提倡无XML配置化。
1.1接口只有一个现实类
可以自动装配
 package demo;
 public interface CompactDisc {
     void play();
 }
实现类
package demo; import org.springframework.stereotype.Component; @Component
6 public class SgtPeppers implements CompactDisc{
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "http://blog.csdn.net/unix21"; public void play() {
System.out.println("【非常醒目SgtPeppers 】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);
}
}
配置类
package demo; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan
public class CDPlayerConfig { }
单元测试类
package demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
@Autowired
@Qualifier("spn")
private CompactDisc cd; @Test
public void play() {
cd.play();
}
}
测试结果

1.2 接口有多个实现类
【参考 Spring实战4 3.3】
故意再写一个实现类
package demo; import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; @Component
public class SgtPeppersNew implements CompactDisc{
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "http://blog.csdn.net/unix21"; public void play() {
System.out.println("【非常醒目SgtPeppersNew 】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);
}
}
此时有两个实现类,如果这时执行单元测试类的时候,测试类不知道注入(DI)那个实现类,所以会报错。
两种解决方案:1,加@Primary 首选标识的bean 2, 使用@Qualifier注解@Qualifier("SgtPeppersNew"), 改变@Component("SgtPeppersNew") 或者@Qualifier 注解中用实现类,但id是小写@Qualifier("sgtPeppersNew"),不需要改变@Component
package demo; import org.springframework.stereotype.Component; @Component
public class SgtPeppersNew implements CompactDisc{
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "http://blog.csdn.net/unix21"; public void play() {
System.out.println("【非常醒目SgtPeppersNew 】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);
}
}
package demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
@Autowired
@Qualifier("sgtPeppersNew")
private CompactDisc cd; @Test
public void play() {
cd.play();
}
}
打印结果

1.3 为组件扫描的bean命名
【参考 Spring实战4 2.2.2】
 import org.springframework.stereotype.Component;  
 @Component("spn")
 public class SgtPeppersNew implements CompactDisc { 
@Autowired
@Qualifier("spn")
private CompactDisc cd;
也可以使用@Named效果是一样的,这是java依赖注入规范
 import javax.inject.Named;  
 @Named("spn")
 public class SgtPeppersNew implements CompactDisc {  
1.4 设定组件扫描的指定包
【参考 Spring实战4 2.2.3】
如果@ComponentScan默认不设置只扫描配置类所在的包作为基础包
@Configuration
@ComponentScan("blog.csdn.net.unix21")
public class CDPlayerConfigTest
设置@ComponentScan的value属性就可以指明包名称。
如果想更清晰的表明设置的是基础包
@ComponentScan(basePackages="指定包")
指定多个
@ComponentScan(basePackages={"指定包1","指定包2"})
也可以将其指定为包中所包含的类或者接口
@ComponentScan(basePackages={"XXX.class","XX.class"})
1.5 自动装配
【参考 Spring实战4 2.2.4】
声明自动装配需要@Autowired注解
1.5.1 在构造方法上使用自动装配
package demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfigTest.class)
public class CDPlayerFunTest {
private CompactDisc cd;
@Autowired
@Qualifier("spn")
public void CDPlayer(CompactDisc cd) {
this.cd = cd;
} @Test
public void play() {
cd.play();
System.out.println("【占位符】CDPlayerFunTest");
}
}

另一种写法
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc cd; @Autowired
public CDPlayer(@Qualifier("spn")CompactDisc cd) {
this.cd = cd;
} public void play() {
cd.play();
} }
1.5.2 在属性Setter方法上使用自动装配
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc cd; @Autowired
@Qualifier("spn")
public void setCompactDisc(CompactDisc cd) {
this.cd = cd;
} public void play() {
cd.play();
}
}
避免异常声明 @Autowired(required = false),如果没有匹配的bean,Spring会让这个bean处于未装配转态,但是需要谨慎对待这个设置,代码需要做null检查。
@Autowired是Spring特有的注解,可以替换为@Inject,@Inject来源自Jave依赖注入规范。
1.6 创建自定义的限定符
【参考 Spring实战4 3.3.2】
@Component
@Qualifier("cold")
public class IceCream implements CompactDisc { private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles"; public void play() {
System.out.println("【非常醒目 IceCream】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfigTest.class)
public class CDPlayerLogTest { @Autowired
private MediaPlayer player; @Autowired
@Qualifier("sp")
private CompactDisc cd; @Autowired
@Qualifier("cold")
private CompactDisc cd2; @Test
public void cdShouldNotBeNull() {
assertNotNull(cd);
} @Test
public void play() {
player.play();
cd.play();
cd2.play();
}
}
好处:这样做的好处限定符不耦合类名,所以可以随意重构类名。
问题:重复的限定符出现在多个类上这是不允许的,因为Java不允许同一个条目上重复出现相同类型的多个注解。
注意:此时我用本地测试时发现 private MediaPlayer player; 这个player 并不能注入到测试类中,需要以后解决。
解决:注意其实CDplayer 也是需要创建的组件类,所以也要加上@Component
1.7 使用自定义限定符注解
针对上述问题可以创建自定义的限定符注解。
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法
@Qualifier
public @interface Cold {}
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法
@Qualifier
public @interface Creamy {}
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法
@Qualifier
public @interface Fruity {}
@Component
@Cold
@Creamy
public class IceCream implements CompactDisc { private String title = "Spring 实现 第4版 读书笔记";
private String artist = "http://blog.csdn.net/unix21"; public void play() {
System.out.println("【非常醒目 IceCream】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);
}
}
@Component
@Cold
@Fruity
public class Popsicle implements CompactDisc { private String title = "Spring 实现 第4版 读书笔记";
private String artist = "http://blog.csdn.net/unix21"; public void play() {
System.out.println("【非常醒目 Popsicle】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfigTest.class)
public class CDPlayerLogTest { @Autowired
private MediaPlayer player; @Autowired
@Qualifier("sp")
private CompactDisc cd; @Autowired
@Cold
@Creamy
private CompactDisc cd2; @Autowired
@Cold
@Fruity
private CompactDisc cd3; @Test
public void cdShouldNotBeNull() {
assertNotNull(cd);
} @Test
public void play() {
player.play();
cd.play();
cd2.play();
cd3.play();
}
}
1.8 bean的作用域
Spring定义了多重作用域,singleton单例,prototype原型等
singleton单例:整个应用中,只创建bean的一个实例,默认Spring上下文中所有的bean都是单例。
prototype原型:每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
@Component
public class Add implements AddI {
public int a=0; public void Add() {
a++;
} public void getA() {
System.out.println("【非常醒目 Add】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>a= " +a+"");
}
}
 public interface AddI {
 void Add();
     void getA();
 }  
@Component
public class CDPlayer implements MediaPlayer { @Autowired
@Qualifier("sp")
private CompactDisc cd; @Autowired
private AddI a; public void play() {
System.out.println("【非常醒目 CDPlayer】>>>");
cd.play();
a.Add();
a.getA();
a.Add();
a.getA();
System.out.println("【非常醒目 CDPlayer】<<<");
}
}
测试用例
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfigTest.class)
public class CDPlayerLogTest { @Autowired
private MediaPlayer player; @Autowired
@Qualifier("sp")
private CompactDisc cd; @Autowired
@Cold
@Creamy
private CompactDisc cd2; @Autowired
@Cold
@Fruity
private CompactDisc cd3; @Test
public void cdShouldNotBeNull() {
assertNotNull(cd);
} @Autowired
private AddI a; @Test
public void play() {
player.play();
cd.play();
cd2.play();
cd3.play();
a.getA();
}
}

再写一个多线程
 public class ClientThread extends Thread {  
     @Autowired
     private AddI a;  
     @Autowired
     public ClientThread(AddI a) {
         this.a = a;
     }  
     public void run() {
         a.Add();
         a.getA();
     }
 }  
调用多线程
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfigTest.class)
public class SpringScopeTest { @Autowired
private AddI a; @Test
public void Scope() {
for (int i = 0; i < 10; i++) {
ClientThread t = new ClientThread(a);
t.start();
}
}
}

此时add实现类如下
@Component
//@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Add implements AddI{
public int a=0;
public void Add() {
// TODO Auto-generated method stub
a++;
} public void getA() {
// TODO Auto-generated method stub
System.out.println("【非常醒目 Add】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>a= " +a+"");
} }
如果使用单例模式则

补充说明:@Repository、@Service、@Controller 和 @Component将类标识为Bean,都是一样的,用在不同的地方而已。
2.AOP切面编程
定义接口
 public interface PerformanceI {
     public void perform();
 } 
实现类
import org.springframework.stereotype.Component; @Component
public class Performance implements PerformanceI{
public void perform(){
System.out.println("【非常醒目 Performance perform 调用中】 By http://blog.csdn.net/unix21");
}
}
定义切面
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; @Aspect
public class MyAspect {
@Before("execution(* com.demo.PerformanceI.perform(..))")
public void before(){
System.out.println("【非常醒目 [方法调用前] 】");
} @After("execution(* com.demo.PerformanceI.perform(..))")
public void after(){
System.out.println("【非常醒目 [方法调用后] 】");
} @AfterThrowing("execution(* com.demo.PerformanceI.perform(..))")
public void afterThrowing(){
System.out.println("【非常醒目 [方法异常后] 】");
}
}
配置文件
import com.demo.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.demo")
public class AppConfig {
@Bean
public MyAspect myAspect() {
return new MyAspect();
} }
测试用例
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class MyTest { @Autowired
private PerformanceI p1; @Test
public void play() {
p1.perform();
}
}
此时在本地运行报错··········
后来加入了 aopalliance.jar 包后解决问题 已经写入到 博客园内 问题3.
实现了方法调用前后的AOP效果。

这个Spring官方参考做的不错:http://docs.spring.io/spring/docs/4.2.5.RELEASE/javadoc-api/
这里选不同的版本:http://docs.spring.io/spring/docs/
4.3.2 创建环绕通知
哈哈此小结个人觉得挺有意思所以也就拿上来了。
环绕通知是最为强大的通知类型。它能够让你所编写的逻辑将被通知的目标方法完全包装起 来。实际上就像在一个通知方法中同时编写前置通知和后置通知。
环绕通知,直接上代码说事情。
package concert; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
@Pointcut("execution(* concert.PerformanceI.perform(..))")
public void perform(){}
@Around("perform()")
public void watchPerformance(ProceedingJoinPoint jp){
try{
System.out.println("【非常醒目 [方法调用前] 】");
jp.proceed();
System.out.println("【非常醒目 [方法调用后] 】");
} catch (Throwable e){
System.out.println("【非常醒目 [方法异常后] 】");
}
}
}
@Around 是环绕通知的 注释,ProceedingJoinPoint 作为参数用来通知“自己想做的业务逻辑” 个人理解就是切点。
粘贴过来一张原图,是通过XML配置来实现AOP切面功能,跟上面 通过基于AspectJ注解 @EnableAspectJAutoProxy 引入是一个意思。
3.Spring MVC
DispatcherServlet是Spring MVC的核心,每当应用接受一个HTTP请求,由DispatcherServlet负责将请求分发给应用的其他组件。
首选给出一张Spring MVC的组件图,也是Spring mvc 的流程图

在旧版本中,DispatcherServlet之类的servlet一般在web.xml文件中配置;但是Spring 3.1引入了注解就无需再使用web.xml文件。
下面配置DispatcherServlet
 import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;  
 public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {  
     @Override
     protected Class<?>[] getRootConfigClasses() {
         return new Class<?>[]{RootConfig.class};
     }  
     @Override
     protected Class<?>[] getServletConfigClasses() {
         return new Class<?>[]{WebConfig.class};
     }  
     @Override
     protected String[] getServletMappings() {
         return new String[]{"/"};
     }  
 }  
Spring 实战4学习笔记(转)的更多相关文章
- 《Spring实战》学习笔记-第五章:构建Spring web应用
		之前一直在看<Spring实战>第三版,看到第五章时发现很多东西已经过时被废弃了,于是现在开始读<Spring实战>第四版了,章节安排与之前不同了,里面应用的应该是最新的技术. ... 
- spring cloud(学习笔记)高可用注册中心(Eureka)的实现(二)
		绪论 前几天我用一种方式实现了spring cloud的高可用,达到两个注册中心,详情见spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一),今天我意外发现,注册中心可以无限 ... 
- 《Angular4从入门到实战》学习笔记
		<Angular4从入门到实战>学习笔记 腾讯课堂:米斯特吴 视频讲座 二〇一九年二月十三日星期三14时14分 What Is Angular?(简介) 前端最流行的主流JavaScrip ... 
- 《机器学习实战》学习笔记第十四章 —— 利用SVD简化数据
		相关博客: 吴恩达机器学习笔记(八) —— 降维与主成分分析法(PCA) <机器学习实战>学习笔记第十三章 —— 利用PCA来简化数据 奇异值分解(SVD)原理与在降维中的应用 机器学习( ... 
- 《机器学习实战》学习笔记第九章 —— 决策树之CART算法
		相关博文: <机器学习实战>学习笔记第三章 —— 决策树 主要内容: 一.CART算法简介 二.分类树 三.回归树 四.构建回归树 五.回归树的剪枝 六.模型树 七.树回归与标准回归的比较 ... 
- Spring源码学习笔记9——构造器注入及其循环依赖
		Spring源码学习笔记9--构造器注入及其循环依赖 一丶前言 前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在 ... 
- Spring 源码学习笔记10——Spring AOP
		Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ... 
- Spring 源码学习笔记11——Spring事务
		Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ... 
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
		Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ... 
随机推荐
- Python作业篇 day03
			###一.有变量name = 'aleX leNb',完成如下的操作 name = 'aleX leNb' name1 = ' aleX leNb ' #1.移除name1 变量对应的值两边的空格 , ... 
- linux上实现jmeter分布式压力测试(转)
			摘要:最近根据公司工作的需求,学习了一些压力测试的知识,目前,公司使用的是jmeter进行压力测试.下面就记录下近期的学习.我想将这次的博文分成三个部分:1.开始测试前的准备(测试环境的搭建)2.在一 ... 
- json object string互转
			参考: https://www.cnblogs.com/guangshan/p/4459436.html JsonArray和JsonObject遍历方法 参考:https://blog.csdn.n ... 
- Linux centosVMware yum更换国内仓库源、yum下载rpm包、源码包安装
			一.yum更换国内仓库源 cd /etc/yum.repos.d/ rm -f dvd.repo wget http://mirrors.163.com/.help/CentOS7-Base-163. ... 
- Linux centosVMware 压缩打包介绍、gzip压缩工具、bzip2压缩工具、xz压缩工具。
			一.压缩打包介绍 Lnux下常见的压缩文件通常是.tar.gz模式,还有.tar..gz..bz2..zip..tar.bz2..tar.xz. .gz:表示由gzip压缩工具压缩的文件 .bz2:表 ... 
- require - 引入文件
			导入 /** * Creates the node for the load command. Only used in browser envs. */ req.createNode = funct ... 
- leetcode200 Number of Islands
			""" Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. ... 
- 03WebDriver
			概述 WebDriver一般用于测试 执行脚本 1.驱动包 WebDriver 不同的浏览器不同的驱动包 2.驱动包技术一个chrome.exe的程序,放到环境变量中,一般放在C:windows里 ... 
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 辅助类:清除浮动1
			<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ... 
- java程序题目解析
			(选择一项) A: 不能有括号 B: C: 确定最后一位 D: 正确答案是 B 本题考查的是Java数组概念,数组下标是从零开始的,但是数据下标的总量和数据长度相同 (选择一项) A: B: 顺序不 ... 
 
			
		