一句话概括:

Spring是一个轻量级的管制反转(IoC)和面向切面(AOP)的容器(框架)。

组成

  • 外围容器:外围容器提供 Spring 框架的基本功能。外围容器的次要组件是 BeanFactory,它是工厂模式的实现。

    BeanFactory 应用管制反转(IOC) 模式将应用程序的配置和依赖性标准与理论的利用程序代码离开。

  • Spring 上下文: 简略了解就是spring的以后运行的环境,也能够了解是spring能够利用的资源。
  • Spring AOP:面向切面的编程性能 ,提供了事务管理服务。

    通过应用 Spring AOP,不必依赖组件,就能够将申明性事务管理集成到应用程序中。

  • Spring DAO:Spring DAO 的面向 JDBC 的异样听从通用的 DAO 异样层次结构。
  • Spring ORM: 对象关系映射(Object Relational Mapping) 。

    用于实现面向对象编程语言里不同类型零碎的数据之间的转换

  • Spring Web 模块:Web 上下文模块建设在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 包容了大量视图技术,其中包含 JSP、Velocity、Tiles、iText 和 POI。

Spring Boot与Spring Cloud

  • Spring Boot 是 Spring 的一套疾速配置脚手架,能够基于Spring Boot 疾速开发单个微服务。
  • Spring Cloud是基于Spring Boot实现的。
  • Spring Boot专一于疾速、不便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架。
  • Spring Boot应用了束缚优于配置的理念,很多集成计划曾经帮你抉择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot能够来到Spring Cloud独立应用开发我的项目,然而Spring Cloud离不开Spring Boot,属于依赖的关系。
  • SpringBoot在SpringClound中起到了承前启后的作用。

IOC

管制反转IoC(Inversion of Control),是一种设计思维,DI是实现IOC的一种办法

  • 管制 : 谁来管制对象的创立 , 传统应用程序的对象是由程序自身管制创立的 , 应用Spring后 , 对象是由Spring来创立的
  • 反转 : 程序自身不创建对象 , 而变成被动的接管对象 .

依赖注入(Dependency Injection,DI) : 就是利用set办法来进行注入的。

IOC是一种编程思维,由被动的编程变成被动的接管

一句话 : 对象由Spring 来创立 , 治理 , 拆卸 !

以前设计一段代码:

//先写一个UserDao接口public interface UserDao {   public void getUser();}//再去写Dao的实现类public class UserDaoImpl implements UserDao {   @Override   public void getUser() {       System.out.println("获取用户数据");  }}//而后去写UserService的接口public interface UserService {   public void getUser();}//最初写Service的实现类public class UserServiceImpl implements UserService {   private UserDao userDao = new UserDaoImpl();   @Override   public void getUser() {       userDao.getUser();  }}

实现类 +++++++ 的时候

都须要批改大量代码 ,这种设计的耦合性太高了,牵一发而动全身 。

咱们能够在须要用到他的中央 , 不去实现它 , 而是留出一个接口 , 利用set , 咱们去代码里批改下 。
public class UserServiceImpl implements UserService {   private UserDao userDao;// 利用set实现   public void setUserDao(UserDao userDao) {       this.userDao = userDao;  }   @Override   public void getUser() {       userDao.getUser();  }}

以前所有货色都是由程序去进行管制创立 , 而当初是由咱们自行管制创建对象 。

程序不必去管怎么创立,怎么实现了 ,它只负责提供一个接口 。

DI

  • 依赖注入(Dependency Injection,DI)。
  • 依赖 : 指Bean对象的创立依赖于容器 , Bean对象的依赖资源 。
  • 注入 : 指Bean对象所依赖的资源 ,由容器来设置和拆卸 。

1、常量注入

<bean id="student" class="com.zwt.pojo.Student">     <property name="name" value="小明"/></bean>           @Test public void test01(){     ApplicationContext context = new               ClassPathXmlApplicationContext("applicationContext.xml");      Student student = (Student) context.getBean("student");      System.out.println(student.getName());  }

2、Bean注入

留神点:这里的值是一个援用,ref。

 <bean id="addr" class="com.zwt.pojo.Address">     <property name="address" value="重庆"/> </bean>  <bean id="student" class="com.zwt.pojo.Student">     <property name="name" value="小明"/>     <property name="address" ref="addr"/> </bean>

3、Properties注入

<property name="info">     <props>         <prop key="学号">20190604</prop>         <prop key="性别">男</prop>         <prop key="姓名">小明</prop>     </props> </property>

…………

p命名和c命名注入

1、P命名空间注入 : 须要在头文件中退出束缚文件

导入束缚 : xmlns:p="http://www.springframework.org/schema/p"  <!--P(属性: properties)命名空间 , 属性仍然要设置set办法--> <bean id="user" class="com.zwt.pojo.User" p:name="zwt" p:age="18"/>

2、c 命名空间注入 : 须要在头文件中退出束缚文件(要写 写有参结构 )

导入束缚 : xmlns:c="http://www.springframework.org/schema/c" <!--C(结构: Constructor)命名空间 , 属性仍然要设置set办法--> <bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>

Bean

在Spring中,那些组成应用程序的主体及由Spring IoC容器所治理的对象,被称之为bean。

简略地讲,bean就是由IoC容器初始化、拆卸及治理的对象 。

几种作用域 :

Singleton

Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的申请,只有id与该bean定义相匹配,则只会返回bean的同一实例。

Singleton是单例类型,就是在创立起容器时就同时主动创立了一个bean的对象,不论你是否应用,他都存在了,每次获取到的对象都是同一个对象。

留神,Singleton作用域是Spring中的缺省作用域。

 <bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

Prototype

示意一个bean定义对应多个对象实例。

Prototype作用域的bean会导致在每次对该bean申请时都会创立一个新的bean实例。

Prototype是原型类型,它在咱们创立容器的时候并没有实例化,而是当咱们获取bean的时候才会去创立一个对象,而且咱们每次获取到的对象都不是同一个对象。

 <bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>      或者   <bean id="account" class="com.foo.DefaultAccount" singleton="false"/>

Request

示意在一次HTTP申请中,一个bean定义对应一个实例。

即每个HTTP申请都会有各自的bean实例,它们根据某个bean定义创立而成。

该作用域仅在基于web的Spring ApplicationContext情景下无效。

 <bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

针对每次HTTP申请,Spring容器会依据loginAction bean的定义创立一个全新的LoginAction bean实例,

且该loginAction bean实例仅在以后HTTP request内无效,

当解决申请完结,request作用域的bean实例将被销毁。

Session

示意在一个HTTP Session中,一个bean定义对应一个实例。

该作用域仅在基于web的Spring ApplicationContext情景下无效。

 <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

针对某个HTTP Session,Spring容器会依据userPreferences bean定义创立一个全新的userPreferences bean实例,

且该userPreferences bean仅在以后HTTP Session内无效。

当HTTP Session最终被废除的时候,在该HTTP Session作用域内的bean也会被废除掉。

主动拆卸

  • 主动拆卸是应用spring满足bean依赖的一种办法
  • spring会在利用上下文中为某个bean寻找其依赖的bean。

Spring中bean有三种拆卸机制,别离是:

  1. 在xml中显式配置;
  2. 在java中显式配置;
  3. 隐式的bean发现机制和主动拆卸。

自动化的拆卸bean :

  1. 组件扫描(component scanning):spring会主动发现利用上下文中所创立的bean。
  2. 主动拆卸(autowiring):spring主动满足bean之间的依赖,也就是咱们说的IoC/DI。

组件扫描和主动拆卸组合施展微小威力,使得显示的配置升高到起码。

举荐应用注解进行主动拆卸

1、在spring配置文件中引入context文件头

xmlns:context="http://www.springframework.org/schema/context"http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd

2、开启属性注解反对!

<context:annotation-config/>

@Autowired

  • @Autowired是按类型主动转配的,不反对id匹配。
  • 须要导入 spring-aop的包!

测试:

public class User {   @Autowired   private Cat cat;      private String str;   public Cat getCat() {       return cat;  }      public String getStr() {       return str;  }}

2、此时配置文件内容

<context:annotation-config/><bean id="dog" class="com.zwt.pojo.Dog"/>

@Autowired(required=false) 阐明:false,对象能够为null;true,对象必须存对象,不能为null。

//如果容许对象为null,设置required = false,默认为true@Autowired(required = false)private Cat cat;

@Qualifier

  • @Autowired是依据类型主动拆卸的,加上@Qualifier则能够依据byName的形式主动拆卸
  • @Qualifier不能独自应用。

1、配置文件批改内容,保障类型存在对象。且名字不为类的默认名字!

<bean id="dog1" class="com.zwt.pojo.Dog"/><bean id="dog2" class="com.zwt.pojo.Dog"/><bean id="cat1" class="com.zwt.pojo.Cat"/><bean id="cat2" class="com.zwt.pojo.Cat"/>

2、没有加Qualifier测试,间接报错

3、在属性上增加Qualifier注解

@Autowired@Qualifier(value = "cat2")private Cat cat;@Autowired@Qualifier(value = "dog2")private Dog dog;

测试,胜利输入!

@Resource

  • @Resource如有指定的name属性,先按该属性进行byName形式查找拆卸;
  • 其次再进行默认的byName形式进行拆卸;
  • 如果以上都不胜利,则按byType的形式主动拆卸。
  • 都不胜利,则报异样。

实体类:

public class User {   //如果容许对象为null,设置required = false,默认为true   @Resource(name = "cat2")   private Cat cat;   @Resource   private Dog dog;   private String str;}

beans.xml

<bean id="dog" class="com.kuang.pojo.Dog"/><bean id="cat1" class="com.kuang.pojo.Cat"/><bean id="cat2" class="com.kuang.pojo.Cat"/><bean id="user" class="com.kuang.pojo.User"/>

测试:后果OK

配置文件2:beans.xml , 删掉cat2

<bean id="dog" class="com.kuang.pojo.Dog"/><bean id="cat1" class="com.kuang.pojo.Cat"/>

实体类上只保留注解

@Resourceprivate Cat cat;@Resourceprivate Dog dog;

后果:OK

论断:先进行byName查找,失败;再进行byType查找,胜利。

小结

@Autowired与@Resource异同:

1、@Autowired与@Resource都能够用来拆卸bean。都能够写在字段上,或写在setter办法上。

2、@Autowired默认按类型拆卸(属于spring标准),默认状况下必须要求依赖对象必须存在,如果要容许null 值,能够设置它的required属性为false。

如:@Autowired(required=false) ,如果咱们想应用名称拆卸能够联合@Qualifier注解进行应用

3、@Resource(属于J2EE复返),默认依照名称进行拆卸,名称能够通过name属性进行指定。

@Autowired先byType,@Resource先byName。

动态and动静代理

AOP的底层机制就是动静代理

动态代理

所谓的代理模式,程序源自于生存

如同现实生活中的你租房子,你看不到房东,然而你仍旧通过代理 租到了房东的房子。

长处:

  • 能够使得咱们的实在角色更加纯正 . 不再去关注一些公共的事件 .
  • 公共的业务由代理来实现 . 实现了业务的分工 ,
  • 公共业务产生扩大时变得更加集中和不便 .

毛病 :

  • 类多了 , 多了代理类 , 工作质变大了 . 开发效率升高 .
//形象角色:租房public interface Rent {   public void rent();}//实在角色: 房东,房东要出租房子public class Host implements Rent{   public void rent() {       System.out.println("房屋出租");  }}//代理角色:中介public class Proxy implements Rent {   private Host host;   public Proxy() { }   public Proxy(Host host) {       this.host = host;  }   //租房   public void rent(){       seeHouse();       host.rent();       fare();  }   //看房   public void seeHouse(){       System.out.println("带房客看房");  }   //收中介费   public void fare(){       System.out.println("收中介费");  }}//客户类,个别客户都会去找代理!public class Client {   public static void main(String[] args) {       //房东要租房       Host host = new Host();       //中介帮忙房东       Proxy proxy = new Proxy(host);       //你去找中介!       proxy.rent();  }}

动静代理

  • 动静代理分为两类 : 一类是基于接口动静代理 , 一类是基于类的动静代理
    • 基于接口的动静代理----JDK动静代理
    • 基于类的动静代理--cglib
    • 当初用的比拟多的是 JAVAssist 来生成动静代理

JDK的动静代理须要理解两个类:

外围 : InvocationHandlerProxy

Object invoke(Object proxy, 办法 method, Object[] args);

proxy - 调用该办法的代理实例

method -所述办法对应于调用代理实例上的接口办法的实例。

办法对象的申明类将是该办法申明的接口,它能够是代理类继承该办法的代理接口的超级接口。

args -蕴含的办法调用传递代理实例的参数值的对象的阵列,或null如果接口办法没有参数。

原始类型的参数蕴含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。

//生成代理类public Object getProxy(){   return Proxy.newProxyInstance(this.getClass().getClassLoader(),                                 rent.getClass().getInterfaces(),this);}

例子:

//形象角色:租房public interface Rent {   public void rent();}//实在角色: 房东,房东要出租房子public class Host implements Rent{   public void rent() {       System.out.println("房屋出租");  }}//ProxyInvocationHandler. java 即代理角色public class ProxyInvocationHandler implements InvocationHandler {   private Rent rent;   public void setRent(Rent rent) {       this.rent = rent;  }   //生成代理类,重点是第二个参数,获取要代理的形象角色!之前都是一个角色,当初能够代理一类角色   public Object getProxy(){       return Proxy.newProxyInstance(this.getClass().getClassLoader(),               rent.getClass().getInterfaces(),this);  }   // proxy : 代理类 method : 代理类的调用处理程序的办法对象.   // 解决代理实例上的办法调用并返回后果   @Override   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {       seeHouse();       //外围:实质利用反射实现!       Object result = method.invoke(rent, args);       fare();       return result;  }   //看房   public void seeHouse(){       System.out.println("带房客看房");  }   //收中介费   public void fare(){       System.out.println("收中介费");  }}/租客public class Client {   public static void main(String[] args) {       //实在角色       Host host = new Host();       //代理实例的调用处理程序       ProxyInvocationHandler pih = new ProxyInvocationHandler();       pih.setRent(host); //将实在角色搁置进去!       Rent proxy = (Rent)pih.getProxy(); //动静生成对应的代理类!       proxy.rent();  }}

外围:一个动静代理 , 个别代理某一类业务 , 一个动静代理能够代理多个类,代理的是接口!

长处:

  • 能够使得咱们的实在角色更加纯正 . 不再去关注一些公共的事件 .
  • 公共的业务由代理来实现 . 实现了业务的分工 ,
  • 公共业务产生扩大时变得更加集中和不便 .
  • 一个动静代理 , 个别代理某一类业务
  • 一个动静代理能够代理多个类,代理的是接口!

AOP

AOP(Aspect Oriented Programming)意为:面向切面编程 。

通过预编译形式和运行期动静代理实现程序性能的对立保护的一种技术。

AOP是OOP的连续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

利用AOP能够对业务逻辑的各个局部进行隔离,从而使得业务逻辑各局部之间的耦合度升高,进步程序的可重用性,同时进步了开发的效率。

作用

提供申明式事务,容许用户自定义切面 。

SpringAOP中,通过Advice定义横切逻辑,Spring中反对5种类型的Advice:

  1. 前置加强 (org.springframework.aop.BeforeAdvice) 示意在指标办法执行前来施行加强
  2. 后置加强 (org.springframework.aop.AfterReturningAdvice)
    示意在指标办法执行起初施行加强
  3. 盘绕加强 (org.aopalliance.intercept.MethodInterceptor)
    示意在指标办法执行前后同时施行加强
  4. 异样抛出加强 (org.springframework.aop.ThrowsAdvice) 示意在指标办法抛出异样起初施行加强
  5. 引介加强 (org.springframework.aop.introductioninterceptor)
    示意在指标类中增加一些新的办法和属性

即 Aop 在 不扭转原有代码的状况下 ,去减少新的性能 。

【重点】应用AOP织入,须要导入一个依赖包!

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --><dependency>   <groupId>org.aspectj</groupId>   <artifactId>aspectjweaver</artifactId>   <version>1.9.4</version></dependency>

第一种形式( 通过 Spring API 实现)

//首先编写咱们的业务接口和实现类public interface UserService {   public void add();   public void delete();}public class UserServiceImpl implements UserService{   @Override   public void add() {       System.out.println("减少用户");  }   @Override   public void delete() {       System.out.println("删除用户");  }    }//而后去写咱们的加强类 , 咱们编写两个 , 一个前置加强 一个后置加强public class Log implements MethodBeforeAdvice {   //method : 要执行的指标对象的办法   //objects : 被调用的办法的参数   //Object : 指标对象   @Override   public void before(Method method, Object[] objects, Object o) throws Throwable {       System.out.println( o.getClass().getName() + "的" + method.getName() + "办法被执行了");  }}public class AfterLog implements AfterReturningAdvice {   //returnValue 返回值   //method被调用的办法   //args 被调用的办法的对象的参数   //target 被调用的指标对象   @Override   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {       System.out.println("执行了" + target.getClass().getName()       +"的"+method.getName()+"办法,"       +"返回值:"+returnValue);  }}//最初去spring的文件中注册 , 并实现aop切入实现 , 留神导入束缚 <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xmlns:aop="http://www.springframework.org/schema/aop"      xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans.xsd       http://www.springframework.org/schema/aop       http://www.springframework.org/schema/aop/spring-aop.xsd">   <!--注册bean-->   <bean id="userService" class="com.zwt.service.UserServiceImpl"/>   <bean id="log" class="com.zwt.log.Log"/>   <bean id="afterLog" class="com.zwt.log.AfterLog"/>   <!--aop的配置-->   <aop:config>       <!--切入点 expression:表达式匹配要执行的办法-->       <aop:pointcut id="pointcut" expression="execution(* com.zwt.service.UserServiceImpl.*(..))"/>       <!--执行盘绕; advice-ref执行办法 . pointcut-ref切入点-->       <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>       <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>   </aop:config></beans>测试public class MyTest {   @Test   public void test(){       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");       UserService userService = (UserService) context.getBean("userService");       userService.search();  }}

Spring的Aop就是将公共的业务 (日志 , 平安等) 和畛域业务联合起来 ,

当执行畛域业务时 , 将会把公共业务加进来 . 实现公共业务的反复利用

畛域业务更纯正 , 专一畛域业务 , 其本质还是动静代理 .

第二种形式 ( 自定义类来实现Aop )

//第一步 : 写咱们本人的一个切入类public class DiyPointcut {   public void before(){       System.out.println("---------办法执行前---------");  }   public void after(){       System.out.println("---------办法执行后---------");  }   }//去spring中配置<!--第二种形式自定义实现--><!--注册bean--><bean id="diy" class="com.zwt.config.DiyPointcut"/><!--aop的配置--><aop:config>   <!--第二种形式:应用AOP的标签实现-->   <aop:aspect ref="diy">       <aop:pointcut id="diyPonitcut" expression="execution(* com.zwt.service.UserServiceImpl.*(..))"/>       <aop:before pointcut-ref="diyPonitcut" method="before"/>       <aop:after pointcut-ref="diyPonitcut" method="after"/>   </aop:aspect></aop:config>      public class MyTest {   @Test   public void test(){       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");       UserService userService = (UserService) context.getBean("userService");       userService.add();  }}

第三种形式(应用注解实现)

//第一步:编写一个注解实现的加强类@Aspectpublic class AnnotationPointcut {   @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")   public void before(){       System.out.println("---------办法执行前---------");  }   @After("execution(* com.kuang.service.UserServiceImpl.*(..))")   public void after(){       System.out.println("---------办法执行后---------");  }   @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")   public void around(ProceedingJoinPoint jp) throws Throwable {       System.out.println("盘绕前");       System.out.println("签名:"+jp.getSignature());       //执行指标办法proceed       Object proceed = jp.proceed();       System.out.println("盘绕后");       System.out.println(proceed);  }}//第二步:在Spring配置文件中,注册bean,并减少反对注解的配置<!--第三种形式:注解实现--><bean id="annotationPointcut" class="com.zwt.config.AnnotationPointcut"/><aop:aspectj-autoproxy/>        

通过aop命名空间的<aop:aspectj-autoproxy />申明

主动为spring容器中那些配置@aspectJ切面的bean创立代理,织入切面。

当然,spring 在外部仍旧采纳AnnotationAwareAspectJAutoProxyCreator进行主动代理的创立工作,

但具体实现的细节曾经被<aop:aspectj-autoproxy />暗藏起来了

<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,示意应用jdk动静代理织入加强,

当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,示意应用CGLib动静代理技术织入加强。

不过即便proxy-target-class设置为false,如果指标类没有申明接口,则spring将主动应用CGLib动静代理。

参考链接:

https://www.bilibili.com/vide...