目录
什么是Spring
spring框架是一个轻量级的框架,他的核心思想是IOC(Inverse Of Control控制反转)和AOP(Aspect Oriented 面向切面编程)。为Java应用程序开发提供组件管理服,用于组件之间的解耦。以及简化第三方JavaEE中间件的使用(JMS,任务调度,缓存,ORM框架),是一个基础架构型的开发框架。
Spring的优势
- 方便解耦,简化开发
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。 - AOP编程的支持
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付 - 声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。 - 方便程序员的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。 - 方便集成各种优秀框架
Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(SpringMVC、Mybatis、Hessian、Quartz 等)的直接支持。 - 降低JavaEE API的使用难度
Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的使用难度大为降低。 - Java源码时经典学习案例
编程为了符合企业级标准,高聚合,低耦合
而Spring第一大核心思想就是IOC-控制反转 DI-依赖注入
SpringIOC容器:将所有的JavaBean注入Spring容器进行"解耦"管理,Spring万物皆为Bean
搭建Spring环境的步骤有两步-坐标的导入与配置文件的创建
<!--spring坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.26</version> </dependency>
使用SpringIOC容器管理JavaBean步骤
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">
</beans>
- 创建JavaBean
- 将类注入Spring容器
配置语法:<bean id="唯一标识" class="类的完全限定名称"></bean> - 测试
加载Spring主配置文件获取核心对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("配置文件名.xml");
让Spring已解耦的方式进行对象的实例化返回用户
applicationContext.getBean("id");
SpringIOC
IOC的名词解释,作用是解耦,使用IOC容器管理项目组件的耦合关系
IOC(Inversion Of Control,中文解释控制反转)是 Spring框架的核心思想之一,主要用于解耦。IOC是
由Spring框架根据配置文件或者注解来创建Bean对象并管理Bean对象之间的依赖关系。使对象形成松散的关系,实现解耦。
控制:指的是创建对象的控制权
反转:指的是将控制权交给其他外部环境(Spring框架,IOC容器)。
SpringDI
DI(Dependecy Inject,中文解释依赖注入)是对IOC概念的不同角度的描述,
指应用程序描述时,每个Bean对象在被IOC容器注入前都会依赖于另一个Bean对象。
DI的实现方式:
- set注入------->通过set方法维护对象之间的依赖关系
- 构造注入----->通过构造方法维护对象之间的依赖关系
- 属性注入----->不推荐
DI注入的数据类型:
- 注入对象
- 注入基本对象与String
- 注入复杂对象 list、set、array、map、properties
set注入实现步骤:
首先需要给属性提供set的方法,并在Bean标签中配置
配置位置:<bean>此位置</bean>
配置语句:<property 属性名="属性值"></property>
配置属性:
name======》属性名称
value=====》属性值
ref=======》属性值的引用
构造注入DI实现步骤:
给属性提供构造方法,在bean标签内部开启配置
配置位置:<bean>此位置</bean>
配置语法:<constructor-arg 属性名="属性值"></constructor-arg>
配置属性:
name======》构造方法参数名称
index=====》构造方法参数下标
type======》构造方法参数类型
value=====》属性值
ref=======》属性值的引用
springIOC容器对bean管理
一、Bean的自动装配
语法:
autowire="属性值"
default-autowire="属性值"
位置:
bean标签---->局部设置
beans标签--->全部设置
属性:
byName============>通过set方法按照名称自动装配,属性名称与bean的id
byType============>通过set方法按照类型自动装配,属性类型与bean的class
constructor=======>通过构造方法按照自动装类型配,属性类型与bean的class
注意:
- 全局,局部均设置,则就近原则
- 大型项目不建议使用,自动装配可读性低
- 自动装配一般只装配javaBean
二、bean的实例化
2.1通过类的无参构造方法实例化(默认)
2.2通过指定工厂创建对象
2.3通过指定静态工厂创建对象
三、bean的生命周期(单例)
- 实例化
- 属性赋值
- 初始化
3.1接口初始化InitializingBean
3.2属性初始化init-method - 操作使用
- 销毁
5.1接口销毁DisposableBean
5.2属性销毁destory-method
四.bean的作用域
prototype--->单例
singleton--->多例
session----->会话
request----->请求
注解版本
一.注入类
@Component
含义:将注解所修饰的类注入spring容器
位置:类
语法:@Component(value = "id") 如果省略value="id"默认注入的id为类的名称且首字母小写
注意:不可以单独使用 <context:component-scan base-package=""></context:component-scan>
@Repository 注入数据访问层
@Service 注入业务层
@Controller 注入控制层
以上三个注解与@Component功能语法一致
二.注入数据
@Value()
含义:向属性注入基本类型与String
语法:@Value("数据") @Value("${key}")
位置:属性
注意:不能单独使用 <context:property-placeholder location=""></context:property-placeholder>
@Autowired()
替换:自动装配属性
位置:属性
含义:通过“set”方法【set方法可以省略】,按照“类型”自动装配,如果类型冲突则按照"名称"装配
注意:
- 按类型装配如果冲突切换为名称装配
- 按类型装配如果冲突切换为名称装配,如果名称也没有则会抛异常 NoUniqueBeanDefinitionException
- 按类型装配没一个匹配 NoSuchBeanDefinitionException
三.其他注解
@Primary
含义:在类型装配冲突的情况下,此注解所修饰的类作为首选项
位置:类
注意:不能单独用
@Qualifier
含义:按照名称装配
位置:属性
注意:不能单独用
@Resource
含义:按照名称装配
位置:属性
注意:单独用
@Scope
含义:作用域
位置:类
注意:不能单独用
举例:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@PreDestroy
含义:替换destory-method
位置:方法
注意:单独用
@PostConstruct
含义:替换init-method
位置:方法
注意:单独用
四、javaConfig配置类注解
@Configuration
含义:配置类
注意:AnnotationConfigApplicationContext
@ComponentScan(basePackages="com.cc")
替换:<context:component-scan base-package=""></context:component-scan>
@PropertySource("classpath:文件名.properties")
替换:<context:property-placeholder location=""></context:property-placeholder>
@Import(配置类.class)
含义:导入其他配置类
@Bean
含义:注入类;方法返回值为class 方法名称为id
位置:修饰方法
注意:单独使用无需扫描
SpringAOP
AOP(Aspect-Oriented Programming: 面向切面编程):将那些与业务无关, 却为业务模块所共同调用的逻辑(例如事务处理、日志管理、权限控制等)封装抽 取成一个可重用的模块,这个模块被命名为“切面”(Aspect),便于减少系统的 重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性;
Spring AOP 基于动态代理实现:
- 如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和Proxy类);
- 如果被代理的对象,没有实现某个接口,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cglib动态代理的核心是MethodInterceptor接口和Enhancer类);
AOP通知类型
AOP将抽取出来的共性功能称为通知;通知类型:以通知在上下文中的具体位置作为划分
前置通知(Before)
后置通知(After)
返回通知(After-returning)
异常通知(After-throwing)
环绕通知(Around)
AOP连接点(Join point):AOP将所有的方法都视为连接点,不管是接口里面的抽象方法,还是实现类里面的重写方法,都是连接点
AOP切点(Pointcut):AOP将可能被抽取共性功能的方法称为切入点。切入点是连接点的子集
AOP目标对象(Target):就是挖掉功能的方法对应的类生的对象,这种对象是无法直接完成最终工作的
AOP织入(Weaving):就是将挖掉的功能回填的动态过程
AOP切面:切点+通知
SpringAOP的实现步骤
坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.28</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency>
XML版
切点表达式配置语法:
execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))
eg: execution(public void com.apesource.service.ServiceImp.findAll())
1.修饰符可以省略代表任意
execution(返回值 包名称.类名称.方法名称(参数列表))
2.返回值可以使用“*”代表任意
execution(* 包名称.类名称.方法名称(参数列表))
3.包名可以使用“*”代表任意名称
execution(* *.*.*.类名称.方法名称(参数列表))
4.包名可以使用“..”代表任意个数
execution(* *...类名称.方法名称(参数列表))
5.类名与方法名可以使用“*”代表任意
execution(* *...*.*(参数列表))
6.参数列表可以使用".."代表任意个数任意类型
execution(* *...*.*(..))
如果有参数
int======>int
String===>java.lang.String
总结AOP开发过程:
开发阶段(开发者完成)===========我们自己做
- 正常的制作程序
- 将非共性功能开发到对应的目标对象类中,并制作成切入点方法
- 将共性功能独立开发出来,制作成“通知”
- 在配置文件中,声明“切入点”
- 在配置文件中,声明"切入点"与"通知"间的关系(含通知类型),即"切面"
运行阶段(AOP完成)=============spring帮我们做的
- Spring容器加载配置文件,监控所有配置的“切入点”方法的执行
- 当监控到“切入点”方法被运行,使用“代理”机制,动态创建“目标对象”的“代理对象”,根据“通知类别”,在“代理对象”的对应位置将“通知”对应的功能“织入”,完成完整的代码逻辑并运行
<!--开启aop配置-->
<aop:config>
<!--切面-->
<aop:aspect id="main" ref="loggerUtil">
<!--切点-->
<aop:pointcut id="dian" expression="execution(* com.apesource.service.ServiceImp.*(..))"/>
<!--前置通知-->
<aop:before method="beforeMethod" pointcut-ref="dian"></aop:before>
<!--返回通知-->
<aop:after-returning method="afterRrturnMethod" pointcut-ref="dian"></aop:after-returning>
<!--异常通知-->
<aop:after-throwing method="throwMethod" pointcut-ref="dian"></aop:after-throwing>
<!--后置通知-->
<aop:after method="afterMethod" pointcut-ref="dian"></aop:after>
<!--环绕通知-->
<aop:around method="arroundMethod" pointcut-ref="dian"></aop:around>
</aop:aspect>
</aop:config>
注解版
@Aspect(切面)
@Pointcut(value = "execution(* com.cc.service.*.*(..))")(切点,需要配合一个类使用,类名为id)
@Before("dian()")(前置通知)
@AfterReturning("dian()")(返回通知)
@AfterThrowing("dian())")(异常通知)
@After("dian()")(后置通知)
@Around("dian()")(环绕通知,使用注解的话比较推荐环绕通知)
@EnableAspectJAutoProxy(AOP的自动代理,使用注解版时需要写在配置类中)