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原型等

参考:spring中scope作用域

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学习笔记(转)的更多相关文章

  1. 《Spring实战》学习笔记-第五章:构建Spring web应用

    之前一直在看<Spring实战>第三版,看到第五章时发现很多东西已经过时被废弃了,于是现在开始读<Spring实战>第四版了,章节安排与之前不同了,里面应用的应该是最新的技术. ...

  2. spring cloud(学习笔记)高可用注册中心(Eureka)的实现(二)

    绪论 前几天我用一种方式实现了spring cloud的高可用,达到两个注册中心,详情见spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一),今天我意外发现,注册中心可以无限 ...

  3. 《Angular4从入门到实战》学习笔记

    <Angular4从入门到实战>学习笔记 腾讯课堂:米斯特吴 视频讲座 二〇一九年二月十三日星期三14时14分 What Is Angular?(简介) 前端最流行的主流JavaScrip ...

  4. 《机器学习实战》学习笔记第十四章 —— 利用SVD简化数据

    相关博客: 吴恩达机器学习笔记(八) —— 降维与主成分分析法(PCA) <机器学习实战>学习笔记第十三章 —— 利用PCA来简化数据 奇异值分解(SVD)原理与在降维中的应用 机器学习( ...

  5. 《机器学习实战》学习笔记第九章 —— 决策树之CART算法

    相关博文: <机器学习实战>学习笔记第三章 —— 决策树 主要内容: 一.CART算法简介 二.分类树 三.回归树 四.构建回归树 五.回归树的剪枝 六.模型树 七.树回归与标准回归的比较 ...

  6. Spring源码学习笔记9——构造器注入及其循环依赖

    Spring源码学习笔记9--构造器注入及其循环依赖 一丶前言 前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在 ...

  7. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

  8. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  9. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

随机推荐

  1. 40个超有趣的Linux命令行彩蛋和游戏

    40个有趣的Linux命令行彩蛋和游戏,让你假装成日理万机的黑客高手.附一键安装脚本,在树莓派和ubuntu云主机上亲测成功,有些还可以在Windows的DOS命令行中运行. 本文配套B站视频:40个 ...

  2. pytorch梯度下降法讲解(非常详细)

    pytorch随机梯度下降法1.梯度.偏微分以及梯度的区别和联系(1)导数是指一元函数对于自变量求导得到的数值,它是一个标量,反映了函数的变化趋势:(2)偏微分是多元函数对各个自变量求导得到的,它反映 ...

  3. 概率图模型(PGM,Probabilistic Graphical Model)

    PGM是现代信号处理(尤其是机器学习)的重要内容. PGM通过图的方式,将多个随机变量之前的关系通过简洁的方式表现出来.因此PGM包括图论和概率论的相关内容. PGM理论研究并解决三个问题: 1)表示 ...

  4. URL构成及各个协议默认端口

    url的构成:一般来说,http请求都会和URL地址有关,对于url来说一般由下面5个部分构成 .协议:通常就是第一个冒号之前的内容常见协议:http,https(http+ssl),ftp,ssh, ...

  5. java中常用的数据结构--Map

    一.定义: 将键映射到值的对象. 地图不能包含重复的键; 每个键可以映射到最多一个值. public interface Map<K,V> 请注意!!!, Map 没有继承 Collect ...

  6. jQuery设置input的type属性

    $("#inputName").attr("type","text");

  7. ionic3记录之APP运行时网络判断

    判断设备网路是否正常: 安装插件: ionic cordova plugin add cordova-plugin-network-information npm install --save@nat ...

  8. 通过开源项目免费申请 IntelliJ IDEA license(激活码)

    通过github开源项目免费申请 IntelliJ IDEA license(激活码) 我用来申请的github开源项目:https://github.com/Linliquan/springboot ...

  9. 2017北京网络赛 J Pangu and Stones 区间DP(石子归并)

    #1636 : Pangu and Stones 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 In Chinese mythology, Pangu is the fi ...

  10. QQ企业通---DllImport

    1.DllImport 是什么? DllImport是System.Runtime.InteropServices命名空间下的一个属性类,其功能是提供从非托管DLL(托管/非托管是微软的.net fr ...