周六了,又是摸鱼的一天,今天还有点不在状态,脑瓜子迷迷糊糊的,昨晚出去喝可乐桶喝的脑子到现在都不是很正常(奉劝各位可以自己小酌:450ml威士忌+1L多一点可乐刚刚好,可能是我酒量不好),正好没啥事就想整理一下自己的文件夹,发现了很久之前整理的一个spring基础的思维导图,如下:

今天,就以这份思维导图为基础,讲解一下spring基础的内容,好了,我们来看一下**文字和代码**的详细解析吧

**需要这份思维导图的,可以关注公众号:Java架构师联盟,后台回复Java即可**

# 什么是Spring

spring是一个轻量级的控制反转(ioc)和面向切面编程(AOP)的容器框架。

- 轻量:从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的jar文件里发布;并且Spring所需的处理开销也是微不足道的。
- 非入侵:在应用中,一般不需要引用springjar包里的类
- 控制反转:Spring的核心机制,通过控制反转技术促进了松耦合。简单来讲,就是把对象创建的权力交给了容器,让容器来管理对象。
- 面向切面:允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。AOP是基于代理的,通俗一点就是把 核心业务 和 系统服务(日志系统、权限管理等) 分开。

# Spring的核心配置和类

1. **applicationContext.xml**:核心配置文件。作用:用于配置所有的类,这些类可以称为springbean
2. **BeanFactory**:容器的工厂类(接口)。作用:用于创建或获取springbean,即spring管理的对象。
3. **ApplicationContext**:应用上下文(接口)他是BeanFactory的子类 作用:用于创建或获取springbean。功能比BeanFactory强大。**BeanFactory**和**ApplicationContext**的区别: *BeanFactory*:懒加载 需要某个对象再去加载 *ApplicationContext*:非懒加载 一次性加载所有的对象

# Spring IOC

**控制反转**:把对象的创建、销毁的权利交给容器框架,由容器来管理对象的生命周期。ioc不是新的技术,只是一种思想或理念,实现松耦合。

IOC包括**依赖注入**(**DI**,核心) 和 依赖查找。

**DI**:依赖注入,简单来讲就是在spring实例化对象的时候,由容器来设置这些对象的属性。

# spring的注入方式

# 属性的注入(set方法注入)

**前提要有对应的setter方法**

以下为spring配置文件代码 java bean忽略。

```
<bean id="person" class="com.xx.Person">
<property name = "name" value = "xzy"/>
<property name = "coll">
<list>
<value>list</value>
<value>list2</value>
</list>
</property>
<property name = "map">
<map>
<entry key = "age" value = "21" />
</map>
</property>
<property name = "arr">
<array>
<value>java</value>
<value>C++</value>
</array>
</property>
</bean>
```

# 通过构造器注入

需要构造方法,javaBean代码:

```
public class User {
private String name;
private Integer age;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
}
```

配置文件代码:

```
<!--通过构造器的方式-->
<bean id = "user" class = "cn.pojo.User">
<constructor-arg value = "Jay" ></constructor-arg>
<constructor-arg value = "21" />
</bean>
<!--指定下标的方式-->
<bean id="user" class="cn.pojo.User">
<constructor-arg value="44" index="1"/>
<constructor-arg value="Jack" index="0"/></bean>
<!--指定在构造中的参数名称-->
<bean id = "user" class = "cn.pojo.User">
<constructor-arg value="44" name="age" />
<constructor-arg value="xxx" name = "name" />
</bean>
```

# 注入其他类

```
<!--通过构造器注入-->
<bean id = "user" class = "com.xx.User">
<constructor-arg value="Jack"></constructor-arg>
<constructor-arg value="44"></constructor-arg>
<!--引用的方式 设置引用id-->
<property name = "car" ref = "car"></property>
</bean>
<bean id = "car" class = "com.xx.Car">
<property name = "type" value = "BWM"></property>
</bean>

<!--内部声明,用这种方式声明,别的bean不能引用了-->
<property name = "car">
<bean class = "cn.xx.Car">
<property name = "type" value = "红旗"/>
</bean>
</property>
```

# bean元素中的属性

- id:Bean的唯一标识符
- name:通过name对Bean进行管理和配置 name可以多个每个以逗号隔开。
- class:指定了Bean的具体实现类,必须是完整的类名 实用类的全限定名
- scope:设定Bean实例的作用域,其属性有singleton(单例)、prototype(原型)、request、session、和global
Session,默认值为singleton.
- constructor-arg:的子元素,可以传入构造参数实例化 该元素index属性指定构造参数的序号(从0开始).
- property:的子元素,通过调用Bean实例中的setter方法完成属性赋值.
- ref:property、constructor-arg等元素的子元素,该元素中的bean属性用于指定对Bean工厂中某个Bean实例的引用;
- value:property、constructor-arg等元素的子元素,用来直接指定一个常量值;
- list:用于封装List或数组类型的依赖注入。
- set:用于封装Set或数组类型的依赖注入。
- map:用于封装Map或数组类型的依赖注入。
- entry:map元素的子元素 用于设定一个键值对。

# Bean的实例化

# 构造器实例化

Spring容器通过Bean对应的默认构造函数来实例化Bean。

# 静态工厂方式实例化

通过创建静态工厂的方式来创建Bean的实例

```
public class BeanFactory {
public static Bean createBean(){
return new Bean();
}
}
<!--factory-method-->
<bean id = "bean" class = "com.xx.BeanFactory" factory-method = "createBean"></bean>
```

# 实例工厂化方式实例化

不再使用静态方法创建Bean实例,而是采用直接创建Bean实例的方式.

```
public class BeanFactory {
public BeanFactory(){
System.err.println("BeanFactory 工厂实例化")
}
public static Bean createBean(){
return new Bean();
}
}

<!--配置工厂-->
<bean id = "beanFactory" class = "com.xx.BeanFactory" /><!--factory-bean 属性指向配置的实例工厂;factory-method属性确定使用工厂的哪个方法-->
<bean id = "bean" factory-bean="beanFactory" factory-method="createBean"/>
```

# Bean的作用域

# singleton:单例模式

Spring IOC容器中只会存在**一个共享的Bean实例**,无论有多少个Bean引用它,始终指向同一对象。

```
配置文件:
<bean id ="dog" class = "com.bean.Dog" scope="singleton"></bean>

java代码:
public void test(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Dog dog1 = (Dog) ctx.getBean("dog");
System.err.println(dog1);
Dog dog2 = (Dog) ctx.getBean("dog");
System.err.println(dog2);
}

// 输出的结果一致,表明为单例模式。
```

# prototype:原型模式

每次通过Spring容器获取prototype定义的bean时,容器都将创建一个**新的Bean实例**,每个Bean实例都有自己的**属性和状态**。

# request

在一次Http请求中,容器会返回该Bean的**同一实例**。而对不同的Http请求则会产生新的Bean,而且该bean**仅在当前HttpRequest内有效**。
针对每一次Http请求,Spring容器根据该bean的定义创建一个全新的实例,且该实例仅在当前Http请求内有效,而其它请求**无法看到当前请求中状态的变化**,当当前Http请求结束,该bean实例也将会被销毁。

# session

在一次Http Session中,容器会返回该Bean的同一实例。而对不同的Session请求则会创建新的实例,该bean实例**仅在当前Session内有效**。
同Http请求相同,每一次session请求创建新的实例,而不同的实例之间不共享属性,且实例**仅在自己的session请求内有效**,请求结束,则实例将被销毁。

# Bean的装配方式

# 基于XML的装配

两种装配方式:setter注入和构造器注入。

设置注入的两个要求:

- Bean类必须提供一个默认的午餐构造方法
- Bean类必须为需要注入的属性提供对应的setter方法

# 基于注解(annotation)

常见注解:

- @Component 是所有受Spring管理组件的通用形式。
- @Repository 持久层使用,dao层使用。
- @Service 业务类,表示业务层组件,Service层使用。
- @Controller 控制器,表示web层组件
- @Autowired 按照类型来装配
- @Resource 根据名字去装配

# 自动装配

属性值说明语法default 默认值由的default-autowire属性值确定default-autowire=“default”byName根据属性名称自动装配byType根据属性的数据类型自动装配constructor根据构造函数参数的数据类型自动装配no不适用自动装配,必须通过ref元素定义

# Spring AOP

实现**核心业务**和**系统服务**代码之间的分开 通过一种特殊的技术手段来实现核心业务运行时能够实现系统服务的功能;
***aop的本质是代理*** 通过对方法进行拦截、增强来实现的。

# AOP的基本概念

采用**横向抽取机制**,把分散在各个方法中的**相同的代码抽取出来**,然后在编译器或者是运行时再把这些代码应用到所需要执行的地方。

**通知(Advice)**:aop在切点上执行的增强处理。

通知的类型:

- 前通知(methodBeforeAdvice):方法执行前做增强
- 后通知(methodAfterAdvice):方法执行后做增强
- 环绕通知(MethodInterceptor):方法执行前和后做增强
- 返回通知(AfterReturningAdvice): 成功返回后 进行增强
- 异常通知(ThrowsAdvice): 抛出异常后 进行通知

**切点(Pointcut)**:就是带有通知的连接点,就是对那些类 哪些方法做增强。

切点的类型:

基于正则表达式 JdkRegexpMethodPointcut

基于AspectJ的表达式 AspectJExpressionPointcut

**切面(Aspect)**:通常上就是一个类,里面定义了 **通知** 和 **切点**

***AOP = 通知 + 切点***

# AOP案例 java实现

```
// com.bean.User
public class User {
public String login(String name){
return "name is "+ name ;
}
public String login(String name , int pwd){
return "name is "+name+", pwd is "+pwd ;
}
}

// 新建一个环绕通知
public class MyAroundAdivice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation arg0) throws Throwable{
System.err.println("方法执行前:"+arg0.getMethod().getName()+","+arg0.getArguments()[0]);
Object obj = arg0.proceed();
System.err.println("执行完成后...");
return obj;
}
}

// 新建基于AspectJ切点的测试类
@Test
public void test(){
// 1. 声明通知
Advice advice = new MyAroundAdivice();
//2、基于AspectJ声明切点对象
AspectJExpressionPointcut cut = new AspectJExpressionPointcut();
//3、设置表达式
/*返回类型为String类型 com.bean.User的login方法 参数为String类型*/
//cut.setExpression("execution (String com.bean.User.login(String))");
//任意放回类型 com包下包括com子包下 任意方法 任意的参数0~n
cut.setExpression("execution(* com..*(..))");
//4、切点+通知 =AOP
Advisor advisor = new DefaultPointcutAdvisor(cut, advice);
//5、声明代理bean
ProxyFactory proxy = new ProxyFactory(new User());
//6、设置aop
proxy.addAdvisor(advisor);
//7、从代理中获取代理的对象
User user = (User) proxy.getProxy();
user.login("rose");
System.err.println("---------------");
user.login("jack",123);
}
```

AspectJ语法

*这个目录下的,或是类上的所有…任意的多个。0~N个execution (* com.bean.User.login(String,int))对login方法,必须要接收两个参数,且参数的类型必须是Strig,int的,且返回值无限制。且这个方法必须是User这个类的Execution (* com.*.*(…))返回所有的类型 所有在com包下的类,不包含子包 类的所有方法 接收任意多个参数 0~NExecution (* com…*.*(…))在com包下的,包含子包下的所有类的所有方法,所有参数都切入execution(* com…*.*(String)) || execution(* com…*.*(*,int))|| 逻辑或

# AOP案例 基于XML声明式AspectJ

```
<bean id = "user" class = "com.bean.User">
<!-- 定义一个切面 -->
<bean id="myBeforeAdvice" class="com.demo03.MyAdvice"></bean>
<aop:config>
<!-- 配置切入点 -->
<!-- 表达式(用来表示方法) -->
<!-- execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>),返回值,方法名,参数不能少 -->
<!-- *代表:任意值 方法名:全类名.方法名 参数中的..:任意个数,任意类型 -->
<aop:pointcut expression="execution(* com..*(..))" id="myPointcut" />
<!-- 切面配置 -->
<aop:aspect ref="myBeforeAdvice">
<!-- 配置前通知 -->
<aop:before method="doBefore" pointcut-ref="myPointcut" />
<!-- 配置后通知 -->
<aop:after method="doAfter" pointcut-ref="myPointcut" />
<!-- 配置返回通知 -->
<aop:after-returning method="doReturnAfter"
pointcut-ref="myPointcut" />
<!-- 配置环绕通知 -->
<aop:around method="doAround" pointcut-ref="myPointcut" />
<!-- 异常通知 -->
<aop:after-throwing method="doThrowing"
pointcut-ref="myPointcut" throwing="e" />
</aop:aspect>
</aop:config>
</bean>
```

# 基于注解的声明式AspectJ (常用)

注解功能@Aspect注解在类上,声明这是一个切面@Pointcut注解在方法上声明是一个切点,且要声明aspectj的切点表达式@Before前通知@After @AfterRetuning –正确执行成功返回值 @AfterThrow – 错误的执行,抛出异常后通知@Around环绕通知

第一步:新建注解的切面类

```
@Aspect
@Component
public class MyAspect {
//定义一个切入点表达式 使用一个返回值为void,方法体为空的方法来命名切点
@Pointcut("execution(* com..*(..))")
public void myPointCut(){}

//前置通知
@Before("myPointCut()")
public void doBefore(JoinPoint joinPoint)
{
System.out.println("前置通知,方法开始..."+":目标类是"+joinPoint.getTarget()+",被植入的增强方法是:"+joinPoint.getSignature().getName());
}
//后置通知
@After("myPointCut()")
public void doAfter()
{
System.out.println("后置通知,方法结束...");
}
//返回通知
@AfterReturning("myPointCut()")
public void doReturnAfter()
{
System.out.println("返回通知,方法最终结束...");
}
/**
* 环绕通知 ProceedingJoinPoint用来调用被增强的方法
* 必须是Object的返回类型
* 必须接受一个参数,类型为ProceedingJoinPoint
* 必须throws Throwable
*/
@Around("myPointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable
{
System.out.println("环绕通知:begin...");
//执行被增强的方法
Object obj = joinPoint.proceed();
System.out.println("环绕通知:end.....");
return obj;
}
@AfterThrowing(value="myPointCut()",throwing="e")
public void doThrowing(Throwable e){
System.out.println("异常通知......."+e.getMessage());
}
}
```

第二步:xml配置文件

```
<bean id="user" class="com.bean.User"></bean>
<context:component-scan base-package="com.xxx"></context:component-scan>
<!-- 启动基于注解的声明式AspectJ支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
```

第三步:测试方法

```
@Test
public void test1() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xxx/applicationContext.xml");
User user = ctx.getBean("user",User.class);
user.say();
//user.run();
}
```

> 如有问题 请指出

最新文章

  1. 《HelloGitHub月刊》第06期
  2. Mysql 关键字及保留字
  3. C#实现按键精灵的&#39;找图&#39; &#39;找色&#39; &#39;找字&#39;的功能
  4. [原] Android快速开发框架-AndroidFine,GitHub开源
  5. linux中,常用的账号管理命令
  6. 括号配对nyoj2(疑问)
  7. C语言修炼-第2天
  8. 安装win7 ubuntu双系统
  9. Java线程池的原理及几类线程池的介绍
  10. android 中对于采用okhttp时获取cookie并放入webview实现跳过登陆显示页面的功能
  11. oracle--varchar2
  12. [poj 2553]The Bottom of a Graph[Tarjan强连通分量]
  13. 深度神经网络(DNN)模型与前向传播算法
  14. MySQL安装、输入密码闪退、workbench使用
  15. 万类之父——Object
  16. jquery 点击事件切换样式
  17. 【数学建模】MatLab 数据读写方法汇总
  18. boolean表达式与在if条件中的运用
  19. hdu-6165(tarjan+topusort)
  20. 转载关于Python Web后端开发面试心得

热门文章

  1. 【SpringBoot】11-1.Springboot整合Springmvc+Mybatis增删改查操作(下)
  2. python的数据处理一
  3. leetcode93:insert-interval
  4. EFCore自己用的点东西
  5. yum针对软件包操作的常用命令
  6. BPMN开源工作流编辑器bpmn-js落地实践中文文档
  7. 关于BigDecimal转String的准确性问题
  8. 六:Redis配制文件
  9. 3-colorability
  10. 如何在Camtasia中对录制视频添加注释