02spring总结
Spring
简介
spring是一个框架,2002年左右,rod,讨论Java企业级开发的问题(EJB),有点繁琐,继承某个类,实现好几个接口,写一堆方法。(Enterprise JavaBean 企业级开发EJB)
简化我们的开发工作,构建最早版本的spring,获取对象的方式发生极大的改变。
Girl g = new Girl();
//写死的方式
new PrettyGirl();
new YoungGirl();
Pay pay;
pay = new WXpay();
pay = new Alipay();
pay = new 手工支付();
参考论文:spring author
大部分的对象应该从容器中获取,而不是进行Java硬编码。
容器:就由它来写,以后我们要什么,就从这个容器里面拿,在容器里面声明告诉它,给我准备什么。
基础技术
-
Java
-
反射
-
xml
-
xml解析
-
代理
-
大量设计模式
spring:春天到来,新生。
官网:spring.io
基础环境搭建
1.添加spring依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
2.写一个实体类。
3.编写一个spring.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
将对象的创建交给spring容器,在这个配置文件里面去声明我要什么对象。
class:写Java类的全限定类名,它是通过全类名然后使用反射的技术进行创建的。
id:ID就是给这个对象在整个应用程序上下文当中取个名字以方便区分。
-->
<bean class="com.sz.pojo.Girl" id="girl">
<!--<property name="name" value="金泰妍"/>
<!--<property name="age" value="30"/>
</bean>
</beans>
4.通过spring的应用程序上下文对象获取对象。
@Test
public void m1(){
//1.获取上下文对象,spring里面声明对象都需要通过上下文对象获取
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过这个对象获取我们的girl
Girl g = ctx.getBean("girl", Girl.class);
System.out.println(g);
PrettyGirl g1 = ctx.getBean("girl", PrettyGirl.class);
System.out.println(g1);
g1.show();
//不使用spring
PrettyGirl g2 = new PrettyGirl();
g2.show();
}
普通编写VSspring方式编写
普通的获取对象的方式,所有的对象之间的依赖,类之间的依赖关系都是在Java代码里面维护的,很难维护的,如果说我们有替换方案,替换比较困难。
spring获取对象,对象的产生全部是在配置文件里面完成的,其实我们想分析关系,直接在配置文件里面就看出来了。
核心内容
- IOC
- AOP
IOC概念
1.
控制反转:inverse of control 什么控制,谁反转了谁。
控制:创建对象,彼此关系的权利。
传统开发:控制权是在开发人员在程序代码当中进行掌控。new
spring:夺取控制权,反转给spring容器。
- 声明要什么
- spring容器来具体的控制。
改变了编程的方式。
2.
依赖注入(DI)
依赖:其实就是你当前文件class要什么,那么要的这个就是这个文件class的依赖。
注入:这种行为就称之为注入bean
容器
- pojos:自己定义的这些类
- metadata:在spring.xml的配置文件里面写的这些就是元数据。
- 实例化容器:classpath方法…将配置文件传入,实例化完毕.
值的注入metadata
- setter注入(最常用的)
- 必须其字段有对应setter方法才可以完成name setName()
- 通过property子节点完成注入。
- 构造注入
如果没有对应的set方法:
-
注意:
-
- spring默认是通过无参构造器完成对象的创建的
- 如果没有无参构造器
bean元素探讨
属性探讨
- abstract:该bean将无法被实例化。一般来做父bean。
- parent:配合abstract使用,指定它的父bean是谁,将会继承父bean的所有内容。通过ID进行指引。
- destroy-method:指定这个bean最后销毁的时候一定执行的方法,适合于清理工作。触发条件是bean确实被销毁才会发生。
- 容器close会触发。
- refresh也会触发。
- 过时的destroy也可以触发。
- init-method:指定bean的初始化方法,准备性的工作。
- name:别名,可以通过它一样获取。可以写多个。彼此分割可以使用多种分割方式(空格,逗号)。框架默认都是单例模式
- scope:指定范围
- singleton:单例,spring上下文当中,只有一个实例。
- prototype:原型:要一个就新给一个
- lazy-init:true就是spring一上来不会初始化我们的bean,当我们需要它(bean)的时候,spring才会初始化。
- 直接初始化
- 它应用程序启动会慢一点,内存消耗更大一点
- 当我们是同bean的时候会快一些。
- 延迟初始化
- 程序启动快一些,内存消耗更小一点
- 使用bean会慢一些。
- 直接初始化
- depends-on:依赖的bean,如果某一个bean的使用严重依赖于另一个bean的准备的话,就可以配置depends-on.
对于非字面值可以描述的值得注入问题
通过ref指向另外一个bean的ID
关于在spring的配置文件当中单独定义别名
- alias 标签完成
sprig多个配置文件里面的bean是可以互相引用的(被上下文扫描到的前提下)
两种注入方式
-
setter
-
构造注入
-
构造方式注入一:
-
-
构造注入方式二:
-
它优先使用了后面的构造器,最好不要用。
-
构造注入方式三:
-
构造函数的里面入参的数据类型定义
-
spring当中各种值的注入
- 数组
- List
- Set
- Map
如果其对应的值是简单的字面值,就直接写就可以了,如果是一个其它的类,那么使用内部bean的方式完成。
自动注入
- byType:按照数据类型进行注入
- byName:按照bean对应的pojo里面的属性的名字来进行匹配
- Constructor
- 优先按照类型去匹配,如果匹配到一个那么直接注入,不止一个按照名字注入,如果一个都找不到,注入失败。
- default
- no:不注入
常用注解
- component(就是一个组件)
- controller(springMVC)
- service(业务层)
- repository(dao层)
零碎的知识点
-
如何引入外部properties
-
-
如何通过表达式引用外部properties的键值
-
-
从一个配置文件引入多个spring配置文件
-
-
配置扫描包
-
-
beanfactory与applicationContext之间的区别
参考官方回答
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"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task"
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-4.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
<!--1.aop是基于代理完成的,所以我们要**我们自动代理-->
<aop:aspectj-autoproxy/>
<!--2.注册一个切面要使用的类,也就是刀工具-->
<bean class="com.sz.advice.BeforeAdvice" id="beforeAdvice"></bean>
<bean class="com.sz.advice.AfterAdvice" id="afterAdvice"></bean>
<bean class="com.sz.advice.AfterReturningAdvice" id="afterReturningAdvice"></bean>
<bean class="com.sz.advice.ExceptionAdvice" id="exceptionAdvice"></bean>
<bean class="com.sz.advice.AroundAdvice" id="aroundAdvice"></bean>
<!--3.注册切点,被切的是哪个,如果不在这个spring.xml也就是容器里面注册,则没有这个特点,不被容器管理-->
<bean class="com.sz.service.ProviderService" id="providerService"></bean>
<bean class="com.sz.service.HelloService" id="helloService"></bean>
<!--4.配置切入方法,切入点,真正携带具体方法的切入面的等信息-->
<aop:config>
<aop:aspect ref="beforeAdvice">
<!--aop:before 表明它确实是前置通知-->
<!--method:指明它使用哪个方法来切。-->
<!--pointcut:切入点,你要什么包下面的什么类下面的什么方法。-->
<!--pointcut="execution(* *.*.*.*.*(..)) 1* 任意返回类型,2* 任意(例如com),3* 任意(例如sz),
4* 任意(advice),5* 任意类(AfterAdvice),6* 任意方法(method),7(..) 任意参数
(实验证明,包装类和基本数据类型,对于execution是严格区分的)-->
<!--如果有多个同类型的建议,谁在前,谁先执行-->
<aop:before method="methodBefore" pointcut="execution(* *.*.*.*.*(..))"></aop:before>
<aop:before method="argsBefore" pointcut="execution(* *.*.*.*.*(..))"></aop:before>
</aop:aspect>
<aop:aspect ref="afterAdvice">
<aop:after method="methodAfter" pointcut="execution(* com.*.*.*.*(..))"></aop:after>
</aop:aspect>
<aop:aspect ref="afterReturningAdvice">
<!--这里定义的returning标签给的value,是从被切得那边return过来赋给的value,
然后具体切的方法再通过参数的形式获取这个值,最后打印出来。returning可以对返回值进行绑定-->
<aop:after-returning method="afterReturning" pointcut="execution(* com.*.*.*.*(..))" returning="returning"></aop:after-returning>
</aop:aspect>
<aop:aspect ref="exceptionAdvice">
<aop:after-throwing method="execep" pointcut="execution(* com.*.*.*.*(..))"></aop:after-throwing>
</aop:aspect>
<aop:aspect ref="aroundAdvice">
<!--默认代替被切的那个类方法,around将其绕过,不执行被切的方法体-->
<aop:around method="around" pointcut="execution(* com.*.*.*.*(..))"></aop:around>
</aop:aspect>
</aop:config>
</beans>
总结xml方式的aop
1.aop依赖,也就是jar包
2.springContext.xml也就是spring配置文件
3.aop是基于代理完成的,所以我们要**自动代理。aop:aspectj-autoproxy/
4.切面,也就是切东西的工具,也就是Java中的一个类,切面中可以定义各种方法,也就是切法,怎么去切。
5.切入点,也就是被切的对象,这里可以定范围包,也可以精确到哪个类。这里需要配置用哪个切面,用切面的哪个方法,共5种,分别是(方法之前,方法之后,返回值之后,异常之后,环绕trycatch(这个可以控制任何时候)),切的是谁,也就是切入点(一个或多个)
6.注意点:所有的切面或者切入点的类,都得在spring.xml中注入才能使用AOP
AOP注解实现
execution表达式
先写访问修饰符 包名的限定 类名 方法名 参数列表 + 组合条件符合,同事符合两个条件,多个条件合一个都可以。
public com.sz..*.*(java.lang.String)
访问修饰符为public的并且是sz这个包或者子包下面的任意类的任意方法的参数为一个,并且类型为String的方法,就可以切割。
public com.sz.*.*()
protected com.sz.*.*()
protected com.sz.*.*.*(java.lang.Integer,..)
注意保证最后一个.*代表的是方法就可以了。依次往前面推。
@Before("execution(* com.*.*.*(..))")
表示com包下的任意包下的任意类的任意方法任意参数,任意返回类型。
@Before("execution(* com..*.*(..))")
表示com包(包含子包)下的任意类下的任意方法下的任意参数,任意返回类型。
常见注解总结
- Configuration:标明一个类为要给配置类,然后程序启动的时候只要扫描这个类,就可以清楚所有的配置规则
- Component:标明一个类为spring的一个组件,可以被spring容器所管理,它是要给普通组件的语义。
- Service:同上,语义上属于服务层
- Repository:同上,语义上属于DAO层
- Controller:同上,语义上属于控制层
- ComponentScan:组件扫描,可以绝对去扫描哪些包
- Bean:用于在spring容器当中注册一个Bean
- Autowired:自动注入组件。