Java进阶笔记(三):Spring相关

【总体部分】

Spring框架的目的:让开发者专注于业务,而不是基本实现。

------------------

Spring的优势:

方便解耦,简化开发

支持AOP编程

支持声明式事务(@Transactional)

方便程序测试(Junit)

方便集成其它优秀框架

降低JavaEE API的使用难度(spring封装了一些jdk中的方法)

------------------

Spring可分为4个模块(开发时只需要引入需要的模块即可):

Web(MVC、WebSocket、Servlet等)、Data Access(jdbc等数据操作相关)、Core Container(Core、Context等核心部分)、Test

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

【IoC部分】

IoC(控制反转)的作用:解决对象之间的耦合问题。

例子:直接new实现类(XXXServiceImpl),当需要变更实现类(例如名称发生变化,要使用XXXServiceImpl2),所有new的地方也需要修改,这是强耦合;

而使用IoC后,不需要new实现类,只需要将接口类写入xml中,然后从工厂中获取即可,达到了解耦的目的。

<beans>

  <bean id="xxxService" class="com.test.service.impl.XXXServiceImpl"></bean>

</beans>

只需要修改配置文件中的"XXXServiceImpl"为"XXXServiceImpl2"即可,只有一个地方。(其它地方是根据id从工厂中拿出来的,无需修改)

------------------

IoC和DI的区别:

DI:Dependency Injection(依赖注入)

IOC和DI描述的是同一件事情,但是角度不一样;IoC是对象的角度(不用自己创建对象了),DI是容器的角度(容器把对象依赖的其它对象注入)

------------------

spring中IoC的配置方式:

1.使用xml

2.使用xml+注解

3.使用纯注解

目的就是将类对象交给spring管理,将对象依赖关系交给spring实现。(@Component/@Controller/@Service/@Repository,@Autowired/@Resource)

使用对象时,从spring工厂获取。

------------------

Spring中Bean的生存周期(xml中可以用scope定义bean的作用范围):

singleton:单例,IOC容器中只有一个该类对象【默认为这个】

prototype:原型(多例),每次使用该类的对象(getBean),都返回一个新的对象【spring只负责创建,不负责管理这种类型的对象】

request:web应用中使用,指明bean的生命周期为request;基本不用

session:web应用中使用,指明bean的生命周期为session;基本不用

application:web应用中使用,指明bean的生命周期为application;基本不用

websocket:web应用中使用,指明bean的生命周期为websocket;基本不用

------------------

使用xml注入bean,配置<bean>标签时:

init-method:可以指定bean被初始化时调用的方法

destroy-method:可以指定bean被销毁时调用的方法(只有当对象为singleton时才有效)

------------------

使用xml注入bean,给bean中的变量设置值时,set注入方式需要使用property标签,注入普通属性使用value,注入另外一个bean使用ref。

<bean id="..." class="...">

  <property name="username" value="abc"/>

  <property name="JavaBean" ref="javaBean"/>  

</bean>

构造器注入方式,需要使用constructor-arg标签,index可根据参数顺序传值,也可以使用name(同上)。

<bean id="..." class="...">

  <constructor-arg index="0" value="abc"/>

  <constructor-arg index="1" ref="javaBean"/>  

</bean>

------------------

第三方jar包的bean可以定义在xml中,交给spring管理,例如Druid连接池。

------------------

xml中用bean标签配置的对象,等价于用@Component写在相应的类文件中。

@Component注解有三种别名,可以用来区分,分别是@Controller(控制层),@Service(服务层),@Repository(Dao层)

------------------

@Autowired与@Resource:

将类对象注入spring容器后,使用注解@Autowired,@Resource注入其它有依赖关系的对象。

@Resource默认按照名称注入(id),【jdk11中移除了,想使用的话需要引入jar包,javax.annotation-api】

@Autowired按照类型注入,如果按照类型无法锁定唯一对象,可以结合@Qualifier指定具体的id

例子:

@Autowired

@Qualifier("xxxDao")

private XXXDao xxxDao;

------------------

spring扫描包语句样例:

在applicationContext.xml中写:

<!-- 开启注解扫描,base-package指定扫描的包路径 -->

<context:component-scan base-package="com.xxx.test" />

<!-- 引入外部资源文件 -->

<context:property-placeholder location="classpath:jdbc.properties" />

<!-- 第三方jar,druid连接池;配置了properties后就可以使用$占位符了 -->

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">

 <property name="driverClassName" value="${jdbc.driver}"/>

 <property name="url" value="${jdbc.url}"/>

 <property name="username" value="${jdbc.username}"/>

 <property name="password" value="${jdbc.password}"/> 

</bean>

------------------

Spring包扫描语句样例2:

如果是WEB应用,则在web.xml中使用以下语句:

<!-- 注解模式需要的参数 -->

<context-param>

  <param-name>contextClass</param-name>

  <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>

</context-param>

<!-- 配置Spring配置类的类名 -->

<context-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>com.xxx.test.SpringConfig</param-value>

</context-param>

<!-- 使用监听器启动spring的IOC容器 -->

<listener>

  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

------------------

Spring中Bean对象的延迟加载(懒加载):配置某个对象的lazy-init,默认是false,创建容器后即初始化对象;设置为true后,当get对象时才初始化该对象。

------------------

IoC容器包括map集合(单例池),beanfactory,BeanPostProcessor等,不只是map集合。

------------------

spring循环依赖问题:(A->B->A)

1.单例bean构造器参数循环依赖(无法解决)

2.prototype原型bean循环依赖(无法解决)

3.单例bean通过setXXX或者@Autowired进行循环依赖,可以解决。

解决方法:三级缓存机制。

(1)创建对象A时,实例化之后就立即放入三级缓存。

(2)创建A途中发现依赖于对象B(A用到了B),查找一二三级缓存没有发现B,则开始创建B对象。

(3)创建B对象途中(实例化后也立即放入三级缓存),发现依赖于对象A,从缓存中查找,在三级缓存中找到了。

(4)从三级缓存找到A后,将A移入二级缓存,同时对A进行一些扩展操作,之后完成对象B的创建。

(5)对象B创建完毕,把自己移入一级缓存。

(6)继续创建对象A,直接拿到创建好的对象B(发现需要B时,缓存中没找到B,就执行创建B的方法,现在执行完毕了,所以直接拿到),之后完成A对象的创建。

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

【AOP部分】

spring中AOP的配置方式:

1.使用xml

2.使用xml+注解

3.使用纯注解

spring使用动态代理实现AOP:

spring实现AOP时,如果被代理对象有接口,会使用jdk动态代理;如果被代理对象没有接口,则使用cglib代理。

使用xml配置AOP步骤:

(1)导入2个jar包,spring-aop和aspectjweaver

(2)创建一个XXXUtils.java,其中写好一些方法,当做切入点方法

(3)在xml中使用bean标签引入XXXUtils.java

(4)在xml中使用aop:config标签,配置切入点方法、方位信息(配置需要在哪个方法之前或之后执行切入的方法)

(5)方位信息可以配置的类型有:前置、后置、异常、最终(无论是否异常都执行)、环绕(其中有个方法可以控制原有业务逻辑是否执行,类似invoke,因此比较灵活)

(6)因此环绕通知不要与普通通知方式混用

(7)aop:pointcut标签中,注意aspectj表达式的用法

---------------------------

xml与注解配置AOP:

1.xml中使用<aop:aspectj-autoproxy/>开启aop注解驱动

2.XXXUtils.java中使用注解配置切面方法

---------------------------

纯注解配置AOP:

在配置类上使用@EnableAspectJAutoProxy注解开启AOP(代替<aop:aspectj-autoproxy/>)

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

【事务部分】

Spring如何实现事务控制:

使用动态代理与AOP思想实现控制,增加3个步骤:

1.关闭jdbc connection自动提交(一个事务要使用一个connection);

//然后执行被代理的事务步骤;

2.发现执行异常则执行rollback();

3.正常执行完毕则执行commit()。

-----------------------------

编程式事务:在业务代码中添加事务控制代码

声明式事务:通过xml或者注解配置的方式达到事务控制的目的

-----------------------------

注解形式配置spring事务:

1.spring配置类上加注解:@EnableTransactionManagement

2.使用@Transactional,可以加在接口上、实现类上、方法上

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

【总结】

Spring到底做了什么:

1.使用反射,创建与管理类对象,配置好类对象之间的依赖关系。(IoC)

2.使用动态代理,增强代码功能,实现事务。(AOP)

原文地址:https://www.cnblogs.com/codeToSuccess/p/13906208.html