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/ ...
随机推荐
- 40个超有趣的Linux命令行彩蛋和游戏
40个有趣的Linux命令行彩蛋和游戏,让你假装成日理万机的黑客高手.附一键安装脚本,在树莓派和ubuntu云主机上亲测成功,有些还可以在Windows的DOS命令行中运行. 本文配套B站视频:40个 ...
- pytorch梯度下降法讲解(非常详细)
pytorch随机梯度下降法1.梯度.偏微分以及梯度的区别和联系(1)导数是指一元函数对于自变量求导得到的数值,它是一个标量,反映了函数的变化趋势:(2)偏微分是多元函数对各个自变量求导得到的,它反映 ...
- 概率图模型(PGM,Probabilistic Graphical Model)
PGM是现代信号处理(尤其是机器学习)的重要内容. PGM通过图的方式,将多个随机变量之前的关系通过简洁的方式表现出来.因此PGM包括图论和概率论的相关内容. PGM理论研究并解决三个问题: 1)表示 ...
- URL构成及各个协议默认端口
url的构成:一般来说,http请求都会和URL地址有关,对于url来说一般由下面5个部分构成 .协议:通常就是第一个冒号之前的内容常见协议:http,https(http+ssl),ftp,ssh, ...
- java中常用的数据结构--Map
一.定义: 将键映射到值的对象. 地图不能包含重复的键; 每个键可以映射到最多一个值. public interface Map<K,V> 请注意!!!, Map 没有继承 Collect ...
- jQuery设置input的type属性
$("#inputName").attr("type","text");
- ionic3记录之APP运行时网络判断
判断设备网路是否正常: 安装插件: ionic cordova plugin add cordova-plugin-network-information npm install --save@nat ...
- 通过开源项目免费申请 IntelliJ IDEA license(激活码)
通过github开源项目免费申请 IntelliJ IDEA license(激活码) 我用来申请的github开源项目:https://github.com/Linliquan/springboot ...
- 2017北京网络赛 J Pangu and Stones 区间DP(石子归并)
#1636 : Pangu and Stones 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 In Chinese mythology, Pangu is the fi ...
- QQ企业通---DllImport
1.DllImport 是什么? DllImport是System.Runtime.InteropServices命名空间下的一个属性类,其功能是提供从非托管DLL(托管/非托管是微软的.net fr ...