Spring

Spring搭建

Spring搭建
https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-local/org/springframework/spring/
1、IOC控制反转:(DI:依赖注入)
2002 Rod Johnon
Spring 2003 ,IOC Aop
Spring data,spring boot,spring cloud,spring framework ,spring social

IOC :控制反转 (DI:依赖注入)

1.搭建Spring环境
下载jar
spring-framework-4.3.9.RELEASE-dist.zip
开发spring至少需要使用的jar(5个+1个):
spring-aop.jar 开发AOP特性时需要的JAR
spring-beans.jar 处理Bean的jar
spring-context.jar 处理spring上下文的jar
spring-core.jar spring核心jar
spring-expression.jar spring表达式
三方提供的日志jar
commons-logging.jar 日志

2.编写配置文件

为了编写时有一些提示、自动生成一些配置信息:
方式一:增加sts插件
可以给eclipse增加 支持spring的插件:spring tool suite(https://spring.io/tools/sts/all)
下载springsource-tool-suite-3.9.4.RELEASE-e4.7.3a-updatesite.zip,然后在Eclipse中安装:Help-Install new SoftWare… - Add

方式二:
直接下载sts工具(相当于一个集合了Spring tool suite的Eclipse): https://spring.io/tools/sts/

新建:bean configuration … - applicationContext.xml

3.开发Spring程序(IOC)

	ApplicationContext conext = new ClassPathXmlApplicationContext("applicationContext.xml") ;
	//执行从springIOC容器中获取一个 id为student的对象
	Student student = (Student)conext.getBean("student") ;

可以发现,springioc容器 帮我们new了对象,并且给对象赋了值

SpringIOC发展史:
1.
Student student = new Student();
student.setXxx();

简单工厂

3.ioc (超级工厂)

IOC(控制反转)也可以称之为DI(依赖注入):
控制反转:将 创建对象、属性值 的方式 进行了翻转,从new、setXxx() 翻转为了 从springIOC容器getBean()
依赖注入:将属性值 注入给了属性,将属性 注入给了bean,将bean注入给了ioc容器;

总结:ioc/di ,无论要什么对象,都可以直接去springioc容器中获取,而不需要自己操作(new\setXxx())

因此之后的ioc分为2步:1 先给springioc中存放对象并赋值 2 拿

DI:依赖注入 ,
Teacher

Course : cname teacher

IOC容器赋值:如果是简单类型(8个基本+String),value;
如果是对象类型,ref=“需要引用的id值”,因此实现了 对象与对象之间的依赖关系

conext.getBean(需要获取的bean的id值)

依赖注入3种方式:
1.set注入:通过setXxx()赋值

赋值,默认使用的是 set方法();
依赖注入底层是通过反射实现的。
<property…>

2.构造器注入:通过构造方法赋值

需要注意:如果 的顺序 与构造方法参数的顺序不一致,则需要通过type或者index或name指定。

3.p命名空间注入
引入p命名空间
xmlns:p=“http://www.springframework.org/schema/p”

简单类型:
p:属性名=“属性值”
引用类型(除了String外):
p:属性名-ref=“引用的id”
注意多个 p赋值的时候 要有空格。

注意:
无论是String还是Int/short/long,在赋值时都是 value=“值” ,
因此建议 此种情况 需要配合 name\type进行区分

示例:
注入各种集合数据类型: List Set map properties

set、list、数组 各自都有自己的标签 ,但是也可以混着用

给对象类型赋值null :

-->注意 没有

赋空值 “”


在ioc中定义bean的前提:该bean的类 必须提供了 无参构造

自动装配(只适用于 ref类型 ):
约定优于配置

自动装配:
<bean … class=“org.lanqiao.entity.Course” autowire=“byName|byType|constructor|no” > byName本质是byId
byName: 自动寻找:其他bean的id值=该Course类的属性名
byType: 其他bean的类型(class) 是否与 该Course类的ref属性类型一致 (注意,此种方式 必须满足:当前Ioc容器中 只能有一个Bean满足条件 )
constructor: 其他bean的类型(class) 是否与 该Course类的构造方法参数 的类型一致;此种方式的本质就是byType

可以在头文件中 一次性将该ioc容器的所有bean 统一设置成自动装配:
<beans xmlns=“http://www.springframework.org/schema/beans”

default-autowire=“byName”>

自动装配虽然可以减少代码量,但是会降低程序的可读性,使用时需要谨慎。

使用注解定义bean:通过注解的形式 将bean以及相应的属性值 放入ioc容器

<context:component-scan base-package=“org.lanqiao.dao”>
</context:component-scan>Spring在启动的时候,会根据base-package在 该包中扫描所有类,查找这些类是否有注解@Component(“studentDao”),如果有,则将该类 加入spring Ioc容器。

@Component细化:

dao层注解:@Repository
service层注解:@Service
控制器层注解:@Controller

=========================================================

1 使用注解实现事务(声明式事务)
目标:通过事务 使以下方法 要么全成功、要么全失败
public void addStudent()
{
//增加班级
//增加学生
//crdu
}

a. jar包
spring-tx-4.3.9.RELEASE
ojdbc.jar
commons-dbcp.jar 连接池使用到数据源
commons-pool.jar 连接池
spring-jdbc-4.3.9.RELEASE.jar
aopalliance.jar

b.配置
jdbc\mybatis\spring
增加事务tx的命名空间

<tx:annotation-driven transaction-manager=“txManager” />

c.使用

将需要 成为事务的方法 前增加注解:
@Transactional(readOnly=false,propagation=Propagation.REQUIRED)

2.AOP:面向方面编程

一个普通的类 -> 有特定功能的类
a.继承类 b.实现接口 c.注解 d.配置

public class MyFilter exntends/implements Xx
{

}

类 -> “通知” :实现接口

前置通知实现步骤:
a.jar
aopaliance.jar
aspectjweaver.jar

b.配置

c.编写
aop:每当之前add()之前 自动执行一个方法log();

addStudent();  业务方法(IStudentService.java中的  addStudent())
before();  自动执行的通知,即aop前置通知

public class Xxx
{
@Test
a(){}
}

如果出现异常:类似java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
则说明缺少jar

后置通知:
a.通知类 ,普通实现接口
b.业务类、业务方法
StudentServiceImpl中的addStudent()
c.配置:
将业务类、通知 纳入springIOC容器
定义切入点(一端)、定义通知类(另一端),通过pointcut-ref将两端连接起来

异常通知:
根据异常通知接口的定义可以发现,异常通知的实现类 必须编写以下方法:
public void afterThrowing([Method, args, target], ThrowableSubclass):

a.public void afterThrowing(Method, args, target, ThrowableSubclass)
b.public void afterThrowing( ThrowableSubclass)

环绕通知: 在目标方法的前后、异常发生时、最终等各个地方都可以 进行的通知,最强大的一个通知;
可以获取目标方法的 全部控制权(目标方法是否执行、执行之前、执行之后、参数、返回值等)

在使用环绕通知时,目标方法的一切信息 都可以通过invocation参数获取到
环绕通知 底层是通过拦截器实现的。

二、实现注解实现 通知 ,aop

a.jar
与 实现接口 的方式相同
b.配置
将业务类、通知 纳入springIOC容器
开启注解对AOP的支持aop:aspectj-autoproxy</aop:aspectj-autoproxy>
业务类 addStudent - 通知

c.编写

通知:
@Aspect //声明该类 是一个 通知
public class LogBeforeAnnotation {

}

注意:通过注解形式 将对象增加到 ioc容器时,需要设置 扫描器
<context:component-scan base-package=“org.lanqiao.aop”></context:component-scan>

扫描器 会将 指定的包 中的 @Componet @Service @Respository @Controller修饰的类产生的对象 增加到IOC容器中
@Aspect不需要 加入扫描器,只需要开启即可:aop:aspectj-autoproxy</aop:aspectj-autoproxy>

通过注解形式 实现的aop,如果想获取 目标对象的一些参数,则需要使用一个对象:JointPoint

注解形式的返回值:
a.声明返回值 的参数名:
@AfterReturning( pointcut= “execution(public * addStudent(…))” ,returning=“returningValue” )
public void myAfter(JoinPoint jp,Object returningValue) {//returningValue是返回值,但需要告诉spring
System.out.println(“返回值:”+returningValue );
注解形式实现aop时,通知的方法的参数不能多、少

实现接口形式、注解形式 只捕获声明的特定类型的异常,而其他类型异常不捕获。
cath()

三、通过 配置将 类->通知
基于Schema配置
类似 与 实现接口的方式

接口方式通知:public class LogAfter implements AfterReturningAdvice
Schema方式通知:
a.编写一个普通类 public class LogAfter {}
b.将该类 通过配置,转为一个“通知”

如果要获取目标对象信息:
注解、schema:JoinPoint
接口:Method method, Object[] args, Object target

schema形式 和注解形式相似,不同之处: 注解形式 使用了注册@After, schmema形式进行了多余的配置

=========================================================
web项目搭建

1.Spring开发Web项目 及 拆分Spring配置文件
a.Spring开发Web项目
Web项目如何初始化SpringIOC容器 :思路:当服务启动时(tomcat),通过监听器将SpringIOC容器初始化一次(该监听器 spring-web.jar已经提供)
因此用spring开发web项目 至少需要7个jar: spring-java的6个jar + spring-web.jar,注意:web项目的jar包 是存入到WEB-INF/lib中

web项目启动时 ,会自动加载web.xml,因此需要在web.xml中加载 监听器(ioc容器初始化)。

Web项目启动时,启动实例化Ioc容器:

contextConfigLocation classpath:applicationContext.xml org.springframework.web.context.ContextLoaderListener

b.拆分Spring配置文件
java项目:
applicationContext1.xml
applicationContext2.xml
applicationContext3.xml

ApplicationContext conext = new ClassPathXmlApplicationContext(“applicationContext3.xml”) ;

Web项目:
	根据什么拆分?
	i.三层结构   
		UI(html/css/jsp  、Servlet)  applicationController.xml
		Service :applicationService.xml
		Dao:applicationDao.xml
		公共 数据库:applicationDB.xml

	ii.功能结构
		学生相关配置 applicationContextStudent.xml   <bean id=""  class="X...Student">
		班级相关配置 applicationContextClass.xml 

	合并:如何将多个配置文件 加载
		(1)
	  <context-param>
	<!--  监听器的父类ContextLoader中有一个属性contextConfigLocation,该属性值 保存着 容器配置文件applicationContext.xml的位置 -->

contextConfigLocation

classpath:applicationContext.xml,
classpath:applicationContext-Dao.xml,
classpath:applicationContext-Service.xml,
classpath:applicationContext-Controller.xml

	(2)推荐
contextConfigLocation classpath:applicationContext.xml, classpath:applicationContext-*.xml
	(3)只在web.xml中加载主配置文件,
	<param-value>
		classpath:applicationContext.xml
	
	</param-value>
	然后在主配置问加中,加载其他配置文件
		<import resource="applicationContext-*.xml"/>
	
		
				

	





Web项目:

2.Spring整合MyBatis

================================================================
Spring - MyBatis

思路:
SqlSessionFactory -> SqlSession ->StudentMapper ->CRUD
可以发现 ,MyBatis最终是通过SqlSessionFactory来操作数据库,
Spring整合MyBatis 其实就是 将MyBatis的SqlSessionFactory 交给Spring

SM整合步骤:
1.jar
mybatis-spring.jar spring-tx.jar spring-jdbc.jar spring-expression.jar
spring-context-support.jar spring-core.jar spring-context.jar
spring-beans.jar spring-aop.jar spring-web.jar commons-logging.jar
commons-dbcp.jar ojdbc.jar mybatis.jar log4j.jar commons-pool.jar

2.类-表

3.MyBatis配置文件conf.xml

4.通过mapper.xml将 类、表建立映射关系

之前使用MyBatis: conf.xml ->SqlSessionFacotry

现在整合的时候,需要通过Spring管理SqlSessionFacotry ,因此 产生qlSessionFacotry 所需要的数据库信息 不在放入conf.xml 而需要放入spring配置文件中

配置Spring配置文件(applicationContext.xml)

6.使用Spring-MyBatis整合产物开发程序
目标:通过spring产生mybatis最终操作需要的 动态mapper对象(StudentMapper对象)
Spring产生 动态mapper对象 有3种方法:

a.第一种方式
DAO层实现类 继承 SqlSessionDaoSupport类

	 SqlSessionDaoSupport类提供了一个属性 SqlSession

b.第二种方式
就是省略掉 第一种方式的 实现类
直接MyBatis提供的 Mapper实现类:org.mybatis.spring.mapper.MapperFactoryBean
缺点:每个mapper都需要一个配置一次

c.第三种方式

批量配置 实现类

=======================================================

Spring IoC容器?
两种形式:
xml配置文件:applicationContext.xml
存bean:
取bean:
ApplicationContext context= new ClassPathXmlApplicationContext(“applicationContext.xml”);
context.getBean();

注解:带有@Configuration注解的类(配置类)

注意:两种形式获取的Ioc容器是 独立的

存bean
	XXX
取bean

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class) ;

XXX:注解形式 给IoC容器中存放Bean:
1.必须有@Configuration注解(配置类)

2.形式:
	①三层组件加入IOC容器: 给个各类加	注解 、 扫描器识别注解所在包
		a.给三层组件 分别加注解(@Controller、@Service、@Repository -> @Component)
		b.将注解所在包 纳入ioc扫描器(ComponentScan)
			纳入ioc扫描器:  ①xml配置文件 :    <context:component-scan base-package="com.yanqun.controller"  >
</context:component-scan>
逻辑: 在三层类上加注解  ,让ioc识别,扫描器
					②注解扫描器

component-scan:只对三层组件负责

给扫描器指定规则 :
过滤类型:FilterType(ANNOTATION,ASSIGNABLE_TYPE,CUSTOM)

ANNOTATION:三层注解类型@Controller、@Service、@Repository -> @Component

excludeFilters:排除
includeFilters:有默认行为,可以通过useDefaultFilters = false禁止

ASSIGNABLE_TYPE:具体的类(StudentService.class)

区分:
ANNOTATION:Controller.clss 指的是 所有标有@Controller的类
ASSIGNABLE_TYPE:值得是具体的一个类 StudentController.class

CUSTOM自定义:自己定义包含规则
@ComponentScan.Filter(type= FilterType.CUSTOM ,value={MyFilter.class}

MyFilter implements TypeFilter 重写其中的match,如果return true则加入IoC容器

	②非三层组件(Student.class 、IntToStringConver.class):

		i.  @Bean+方法的返回值 ,id默認就是方法名(可以通过@Bean("stu") 修改id值)
		ii. import 、FactoryBean

bean: 类
a. 非三层组件 :Student\Teacher\配置信息 : @Bean
b. 三层组件 :Controller、Service、Dao :@Component(@Controller、@Service、@Repository)

三层组件
a.加入@Component等注解
b.配置,让容器识别注解
i.XML形式:通过扫描器 将@Component等注解所在包 扫描
<context:component-scan base-package=“com.yanqun” >

			</context:component-scan>
		
			
	ii.注解
		@Configuration

@ComponentScan(value=“com.yanqun”)
public class MyConfig {…}

component-scan指定规则:

FilterType :
ANNOTATION:指定类型 (@Compent @Controller @Service @Repository)
ASSIGNABLE_TYPE :自定义类的类中选 StudentDao
ASPECTJ,
REGEX,
CUSTOM:自定义形式 :a.@ComponentScan.Filter(type= FilterType.CUSTOM,classes ={ MyFilter.class })},useDefaultFilters = false)
b.MyFilter implements TypeFilter 重写match()方法,如果返回值true

@Component(@Controller、@Service、@Repository):三层组件
非三层组件


–bean的作用域

scope:  singleton| prototype

执行时机(产生bean的时机):
singleton:容器在初始化时,就会创建对象(唯一的一个);以后再getBean时,不再产生新的bean。singleton也支持延迟加载(懒加载):在第一次使用时产生。 @Lazy
prototype:容器在初始化时,不创建对象;只是在每次使用时(每次从容器获取对象时 ,context.getBean(Xxxx)),再创建对象;并且 每次getBean()都会创建一个新的对象。

–条件注解 Spring Boot
可以让某一个Bean 在某些条件下 加入Ioc容器,其他情况下不加IoC容器。
a.准备 bean
b.增加条件Bean:给每个Bean设置条件 ,必须实现Condition接口
c.根据条件,加入IoC容器

–回顾给IoC加入Bean的方法
注解 :全部在@Congiration配置中设置:
三层组件: 扫描器 + 三层注解
非三层组件: ① @Bean+返回值
②@import
③FactoryBean(工厂Bean)

@import使用:
①直接编写到@Import中,并且id值 是全类名
②自定义ImportSelector接口的实现类,通过selectimports方法实现(方法的返回值 就是要纳入IoC容器的Bean) 。 并且 告知程序 自己编写的实现类。 @Import({Orange.class,MyImportSelector.class})
③编写ImportBeanDefinitionRegistrar接口的实现类,重写方法
@Import({Orange.class,MyImportSelector.class,ImportBeanDefinitionRegistrar.class})

–FactoryBean(工厂Bean)
1.准备bean。实现类和重写方法 2.注册bean。注册到@Bean中
注意:需要通过&区分 获取的对象是哪一个 : 不加&,获取的是最内部真实的Apple;
如果加了&,获取的 是FacotryBean

–IoC容器:初始化容器、…使用容器、销毁容器

—Bean的生命周期:创建(new …)、初始化(赋初值)、 …、销毁 (servlet)
方法一: Student.java
适用于:@Bean+返回值方式
init destroy
xml:
init-method=“myInit” destroy-method=“myDestroy”
注解:
@Bean(value=“stu”,initMethod = “myInit”,destroyMethod = “myDestroy”)

IoC容器在初始化时,会自动创建对象(构造方法) ->init ->…->当容器关闭时 调用destroy…

方法二:
三层注解 (功能性注解、MyIntToStringConverter.java):@Controller、@Service、@Repository、@Component

–>三层注解(功能性注解【三层、功能性类】)
三层组件: 扫描器 + 三层注解(4个)

JAVA规范 :JSR250

1.将响应组件 加入 @Component注解、 给初始化方法加@PostConstruct、给销毁方法加@PreDestroy
@PostConstruct:相当于方法一的init
@PreDestroy:相当于方法一的destroy

如果要获取@Component注解中的bean,那么该Bean的名字就是@Component(value="xxx")的value值

方法三:两个接口
接口:适用于三层组件(扫描器+三层组件)
InitializingBean初始化
DisposableBean 销毁

初始化:只需要 实现InitializingBean中的afterPropertiesSet()方法
销毁:实现DisposableBean 中的destroy()方法

问题:要在SPring IOC容器中操作:操作方式 对象:Bean+返回 ,三层组件

->如果是注解形式 , 随便写一个方法 ,然后加上相应注解即可
如果是接口形式,必须 实现接口中规定的方法

方法四:(给容器中的所有Bean加初始化、销毁)一个接口
接口:适用于三层组件
接口BeanPostProcessor:拦截了所有中容器的Bean

—自动装配 : 三层组件(4个注册+扫描器)
@Autowired
Controller->Service->Dao
三层组件
通过@Autowired从Ioc容器中 根据类型自动注入(没有调用setXxx()方法)
-如果@Autowired在属性前标注,则不调用setXxx;如果标注在setXxx前面 ,则调用setXxx
-不能放在方法的参数前
@Autowired
private Xxx xx;

public void aa()
{

}

@Autowired
public void setXxx(xx xx)
{

}

Bean+返回值:
@Autowired 在方法的参数前(也可以省略)、方法前 (构造方法:特殊,如果只有一个有参构造方法,则构造方法前的@Autowired也可以省略)

public void setXxx(@Autowired xx xx)
{

}

之前:@Autowired 根据类型匹配:
三层注入方式/@Bean+返回值
1.如果有多个类型相同的,匹配哪个?
报错。 /默认值@primary
2.能否根据名字匹配?
可以,结合 @Qualifier(“stuDao2”)使用。

		3.如果有0个类型相同,默认报错;可以修改成不注入(null),@Autowired(required=false)

自动注入方式一: @Autowired (Spring) ,默认根据类型
自动注入方式二 @Resource(JSR250),默认根据名字 (如果 有名字,根据名字匹配;如果没有名字,先根据名字查找,如果没找到,再根据类型查找);也可以通过name或type属性 指定根据名字 或类型找。
自动注入方式一: @Inject(JSR330),额外引入javax.inject.jar,默认根据类型匹配

—利用Spring底层组件进行开发 (三层组件)
能够供我们使用的组件,都是Aware的子接口,即XxxxAware
以ApplicationContextAware为例:实现步骤
a.实现ApplicationContextAware,
b.重写其中的方法,都包含了一个对象。只需要将该对象 赋值到属性中即可

有什么用:例如ApplicationContextAware,可以通过该接口 获取到Ioc容器对象。
执行时间:	如果在main()中new Ioc容器: 先执行ApplicationContextAware实现类中的方法,通过该方法传入IoC容器 供我们自己使用;  然后再将该容器通过new返回给用户

BeanNameAware:

–环境切换:@Profile
Spring:切换环境

激活方式一:
-Dspring.profiles.active=@Profile环境名
-Dspring.profiles.active=myApple

数据库环境:
	@Profile
	127.0.0.1  scott  tiger  

	@Profile
	192.168...

激活方式二:
硬编码

坑:错误写法
		        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class) ;

    ConfigurableEnvironment environment = (ConfigurableEnvironment)context.getEnvironment();
    environment.setActiveProfiles("myBanana");

其中AnnotationConfigApplicationContext中有一个refresh()操作:会将我们设置的一些参数还原
没激活 |->进行激活 ->刷新 ->没激活


流程调整:
	没激活->进行激活  |    ->刷新

什么时候设置 保存点|: 配置类的编写处
IoC容器在使用时必须refresh() ;如果是有参构造,内部已经刷新;如果无参构造,需要手工刷新。

—Spring重要组件
接口BeanPostProcessor:拦截了所有中容器的Bean,并且可以进行bean的初始化 、销毁
创建->初始化->…-》销毁
BeanPostProcessor
BeanFactoryPostProcessor:拦截了容器
BeanDefinitionRegistryPostProcessor:即将被加载之前(解析之前,称为BeanDefination对象之前)

BeanDefinitionRegistryPostProcessor(a) -》加载bean->BeanFactoryPostProcessor(b)->实例化bean->BeanPostProcessor
同一个方法 在不同地方(类、接口)的出现时机问题:a继承b,因此a中必然包含b中的方法(记c ):虽然a和b中都有c,但是 因此c出现的时机不同, 则c的执行顺序也不同: 如果是在a中出现,则先执行;如果是在b中执行 则后执行

在同一个地方(类、接口),的不同方法的出现时机问题

监听器:
可以监听事件 ,监听的对象必须是 ApplicationEvent自身或其子类/子接口
方式一:
1必须实现ApplicationListener接口,

方式二:注解

(语法上 可以监听任意事件,但建议 ApplicationEvent自身或其子类/子接口)
Spring:要让SPring识别自己,必须加入IOc容器(Bean+返回值| 注解+扫描器)

自定被监听事件
a.自定义类 实现ApplicationEvent接口(自定义事件)
b.发布事件
context.publishEvent(自定义事件);

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金石不渝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值