面试题一浏
- Spring aop是什么以及它的底层原理
AOP(Aspect Oriented Programming)面向切面编程 AOP适合于那些具有横切逻辑的应用: 如性能监测,访问控制,事务管理、缓存、对象池管理以及日志记录。AOP将这些分散在各个业务逻 辑中的代码通过横向切割的方式抽取到一个独立的模块中
AOP(这里的AOP指的是面向切面编程思想,而不是Spring AOP)主要的的实现技术主要有Spring AOP和AspectJ /ˈæspekt/。
Aspectj: AspectJ的底层技术是静态代理,即用一种AspectJ支持的特定语言编写切面, 通过一个命令来编译,生成一个新的代理类,该代理类增强了业务类,这是在编译时增强,相对于下面说的运行时增强,编译时增强的性能更好。
Spring AOP:采用的是动态代理,在运行期间对业务方法进行增强,所以不会生成新类,对于动态代理技术, Spring AOP提供了对JDK动态代理的支持以及CGLib的支持。 JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被代理目标类的接口信息 (应用Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用实现了InvocationHandler接口的方法来处理。 CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成子类。是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。 因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
- sping常用注解的原理
启动spring容器,并且加载配置文件
当解析到<context:annotation-config></context:annotation-config>
会启动依赖注入的注解解析器
会在纳入spring管理的bean的范围内查找看哪些bean的属性上有@Resource注解
如果@Resource注解的name属性的值为”",则会把注解所在的属性的名称和spring容器中bean的 id进行匹配
如果匹配成功,则把id对应的对象赋值给该属性,如果匹配不成功,则按照类型进行匹配,如果再匹配不成功,则报错
如果@Resource注解的name属性的值不为”",会把name属性的值和spring容器中bean的id做匹配, 如果匹配
成功,则赋值,如果匹配不成功 ,则直接报错
-
Spring 是如何管理事物的原理是什么
xmind
-
@resource和@autowire的区别是什么
@Resource默认按照名称(name="属性名”)进行装配,名称可以通过@resource的name属性设定,当找不 到与名称匹配的bean才会按类型装配。 1name不正确,但类型正确。
@Autowired按照默认类型(类名称)装配依赖对象,无法设置name,默认情况下它要求依赖对象必须存在,如果允许为 null,可以设置它的required属性为false。(Autowired有多个类型会报错,除非加入了@Qualifier(“id/name”)做限制,或者这个属性的名称可以匹配到容器中的Id/name否则在IDEA编译时就报错)
@Qualifier("容器中的id/name")
,是用来消除依赖注入冲突的,当@Autowired有多个相同类型时就会报错,这时可以用@Qulifier/ˈkwɑːlɪfaɪər/做一个限定。
- 介绍spring
Spring framework是为了解决企业应用开发的复杂性而创建的一个开源框架。
1、Spring的核心是一个轻量级(Lightweight)的、非入侵性(No intrusive)、 IOC(Inversion of Control) 容器(Container)。
2、Spring提供AOP(Aspect-oriented programming)概念的实现方式、提供对持久层(Persistence)、事物(Transcation)的支持。
3、Spring提供MVC Web框架的实现,并对一些常用的企业服务API(Application Interface)提供一致的模型封装。
4、提供了对现有框架的支持,struts2,Hibernate,MyBatis,可以灵活的将它们整合在一起。
-
简单介绍下Spring的IOC的讲述
IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想,就是说,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建,主要目的是为了实现代码之间的解耦。
DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中(java反射原理)。
-
Spring IOC工作原理
同158
-
Spring aop介绍
同149
-
请解释SpringBean的生命周期?
-
请介绍一下Spring框架中Bean的生命周期和作用域
-
BeanFactory和ApplicationContext有什么区别?
-
构造方法注入和设值注入有什么区别?
唯一的区别在于2种方式创建合作者的顺序不同。一般把一个Bean设计为构造函数接收依赖对象时,其实表达了2个对象间的一种强的聚合关系:组合关系。就比如一辆车如果没有轮子、引擎等部件那么车也就不存在了。
如果你的应用中有这样类似的场景那么你应该使用“构造函数注 入”的方式管理他们的关系。“构造函数注入”可以保证合作者先创建,在后再创建自己。若是此时采用设值注入,而忘记设置某个值,这个值为Null,若没注意到这一点,那就等着改BUG吧。
通过set方法注入的方式表达了2个对象间较弱的依赖关系:聚合关系。就像一辆车,如果没有车内音像车也时可以工作的。当你不要求合作者于自己被创建 时,“set方法注入”注入比较合适。
使用构造函数依赖注入时,Spring保证所有一个对象所有依赖的对象先实例化后,才实例化这个对象。(没有他们就没有我原则)
使用set方法依赖注入时,Spring首先实例化对象,然后才实例化所有依赖的对象。
-
Spring 框架中都用到了哪些设计模式?
-
Spring支持的事务管理类型有哪些?你在项目中使用哪种方式?
-
spring配置文件都写什么?
-
Spring中自动装配的方式有哪些?
171spring对多种ORM 框架提供了很好的支持,结合事务管理描述spring中使用Hibernate的方法。
第一章-Spring概述
1什么是Spring?
也可以这样说,Spring是用来做什么的?,简单介绍一下Spring。
进入Spring官网,Spring有很多技术,点击上方的Projects,其中有叫framework [freɪmwɜːrk]的,通常我们所说的spring指的是Spring framework。
答:
Spring framework是为了解决企业应用开发的复杂性而创建的一个开源框架。
1、Spring的核心是一个轻量级(Lightweight)的、非入侵性(No intrusive)、 IOC(Inversion of Control) 容器(Container)。
2、Spring提供AOP(Aspect-oriented programming)概念的实现方式、提供对持久层(Persistence)、事物(Transcation)的支持。
3、Spring提供MVC Web框架的实现,并对一些常用的企业服务API(Application Interface)提供一致的模型封装。
4、提供了对现有框架的支持,struts2,Hibernate,MyBatis,可以灵活的将它们整合在一起。
2七大模块

- 核心容器(Spring core)
核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。BeanFactory使用依赖注入的方式提供给组件依赖。
- Spring上下文(Spring context)
Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring面向切面编程(Spring AOP)
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO模块
DAO模式主要目的是将持久层相关问题与一般的的业务规则和工作流隔离开来。Spring 中的DAO提供一致的方式访问数据库,不管采用何种持久化技术,Spring都提供一直的编程模型。Spring还对不同的持久层技术提供一致的DAO方式的异常层次结构。
- Spring ORM模块
Spring 与所有的主要的ORM映射框架都集成的很好,包括Hibernate、JDO实现、TopLink和IBatis SQL Map等。Spring为所有的这些框架提供了模板之类的辅助类,达成了一致的编程风格。
- Spring Web模块
Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。Web层使用Web层框架,可选的,可以是Spring自己的MVC框架,或者提供的Web框架,如Struts、Webwork、tapestry和jsf。
- Spring MVC框架(Spring WebMVC)
MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。Spring的MVC框架提供清晰的角色划分:控制器、验证器、命令对象、表单对象和模型对象、分发器、处理器映射和视图解析器。Spring支持多种视图技术。
第二章-IOC思想
1什么是IOC?
IOC(Inversion of Control)控制反转,是面向对象编程中的一种设计原则,用来减低代码之间的耦合度,是一种设计思想,包含了两个方面:一、控制。二、反转
- 控制指的是:当前对象对内部成员的控制权。
- 反转指的是:这种控制权不由当前对象管理了,由其他(类,第三方容器)来管理。
先看看之前的使用方式:
1
2
3
4
5
6
7
|
public class LoginServiceImpl implements LoginServiceDao {
UserDao mydao=new MySqImple();
//假如我要换数据库了,OracleImple(),那么我需要在每个用到MySqlImple的类的都要去修改。
public void login (){
mydao.checkUser(String userName);
}
}
|
再看看IOC依赖容器的方式:
1
2
3
4
5
6
7
|
public class LoginServiceImpl implements LoginServiceDao {
UserDao mydao=IOCRepository.getUserDAO();
//如果我需要更换数据库了。只需要在IOCRepository中更换一下实现类就好了。
public void login (){
mydao.checkUser(String userName);
}
}
|
《敏捷软件开发》第11章:
依赖倒置原则
a.高层模块不应该依赖于底层模块,二者都应该依赖于抽象。
b.抽象不应该依赖于细节,细节应该依赖于抽象。
2 IOC的两种方式
IOC(inversion of controller)由于它的最佳实现方式就是依赖注入,通常我们所说的IOC和DL是相互转换的。
2.1依赖查找DL
依赖查找(Dependency Lookup)是指对象本身试图查找依赖关系,例如:
1
2
|
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");
MyBean bean = applicationContext.getBean("myBean")
|
这里,类本身是通过XML初始化ApplicationContext,它在上下文中搜索ApplicationContext中名为myBean的bean.
2.2依赖注入DI
Dependency(/dɪˈpendənsi/) Injection 依赖注入在使用Spring容器的时候,容器通过调用set方法或者是构造器来建立对象之间的依赖关系。
依赖注入也有两种方式Constructor注入和Setter注入
Constructor注入VS Setter注入
●Constructor注入能够强制要求调用者注入构造函数中的所有参数,否则在容器初始化时就会
失败;但是如果要注入的对象过多,就会导致构造函数过于庞大。
●Setter注入,类似于Builder模式,将原本庞大的构造函数,拆解为了-一个小的构造函数和许
多个set坊法。setter注 入不能保证对象一定会被注入,但是可以使用@Required注解,强制
要求使用者注入对象,否则在容器初始化时就会报错。
第三章-IOC使用
1入门
1.0案例和知识点
1
2
3
|
用maven导包
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
|
然后resouces下建立applicationContext.xml,写两个类,LoginServiceImpl依赖OracleImpl
1
2
3
4
5
|
<!--注册Bean Spring是个IOC的容器,那么这个容器需要放哪些东西,需要我们去容器中注册,这个注册就是Bean-->
<bean id="loginServiceDao" class="com.lx.service.LoginServiceImpl" >
<constructor-arg name="mydao" ref="oracleImpl"></constructor-arg>
</bean>
<bean id="oracleImpl" class="com.lx.dao.OracleImpl"></bean>
|
bean有id和class,id是唯一的,首字母小写。
测试: 1创建ApplicationContext有两个类可以实现。有关键字"classpath:",getBean有一个参数和两个参数区别,要加载多个时,“classpath:/*.xml"或者new String[]{“112”,“223”}数组方式。
1
2
3
|
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
OracleImpl oracle=context.getBean("oracleImpl",OracleImpl.class);
oracle.getUserName();
|
ApplicationContext
ClassPathXmlApplicationContext基于xm|方式(配置文件在resource下)
FileSystemXmlApplicationContext基于xml方式(配置文件路径随意)
AnnotationConfigApplicationContext基于注解方式
bean的作用范围和生命周期
●单例对象: scope-“singleton”
一个应用只有一个对象的实例。它的作用范围就是整个引用。
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象- -直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
●多例对象: scope="prototype”
每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就-直活着。
对象死亡:当对象长时间不用时,被java的垃圾回收器回收了.
1.1构造函数注入
第一个Bean依赖于第二个Bean,这里使用的是构造函数注入。
那么对应的第一个Bean所对应的类,需要有无参构造,和有参构造。
1
2
3
4
5
|
//如何传参,这里可以用name去匹配构造函数的name,也可以用index(从0开始)来标明是第几个参数。
LoginServiceImpl(UserDao oracleImpl, String name) {}
<constructor-arg name="mydao" ref="oracleImpl"></constructor-arg>
<constructor-arg index="1" value="oracleImpl"></constructor-arg>
//当参数是一个类时,用ref="这个类在容器用Bean标签注册的id"。
|
1.2setter注入
注意,用setter注入,需要有set方法

1.3Bean标签(xml)
Bean标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<!--
Bean属性介绍:
id: 为对象命名,唯一性标识,不能重复,不能使用特殊字符。
name: 和 id 的作用类似,区别在于可是使用特殊字符,可重复,但是不建议重复。
别名,可以有多个,用逗号或者空格分割。
class: 指定对象的全类名。
init-method: 对象初始化之后立即执行的方法。
destroy-method: 对象销毁之前执行的方法。
scope: 对象的作用范围,可以设置单例 singleton 和多例 prototype。
默认为单例,特殊情况为多例,比如struts2中的action,创建出来不会存在容器中。
还有针对web的request,session把创建对象存到request/session域。
-->
<Bean id="" name="" class="全限定类名com.lx.service.LoginServiceImpl">
<constructor-arg name="mydao" ref="oracleImpl" type=""></constructor-arg>
<constructor-arg index="1" value="oracleImpl"></constructor-arg>
</Bean>
<!--
constructor-arg属性:
name:对应构造方法的参数名称
index:对应构造方法的第几个参数,从0开始
type:为参数指定类型,一般不指定,若是基本参数
-->
|
1
2
|
<!--别名,如果添如了别名,我们也可以使用别名获取到这个对象-->
<alias name="user" alias="userNew"/>
|
1
2
|
导入其他的xml
<import resource="beans. xm1"/>
|
1.4自动装配
- no:不进行自动装配,手动设置Bean的依赖关系。
- byName:根据Bean的名字进行自动装配。 (id,name和属性的setXXX进行装配,找不到会赋为null)
- byType:根据Bean的类型进行自动装配。(多类型会报错)
- default:由上级标签的default-autowire属性确定。
- constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。
- autodetect:</dɪˈtekt/自动检测> 如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。
- **注意:**不能装配基本类型。
2基于注解的开发
前提:使用注解要在applicationContext.xml中导入命名空间,然后加上<context:annotation-config />,开启注解。
1
2
3
4
5
6
7
8
|
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
|
就是把第一行的xmlns复制后,把beans改为context,再在xsi:schemaLocation中把网址复制,把beans修改为context。
2.1@Autowired和@Resource
@Resource默认按照名称(name=”")进行装配,名称可以通过@resource的name属性设定,当找不 到与名称匹配的bean才会按类型装配。(IDEA中Resource写name,name必须存在)
- 有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略
@Autowired按照默认类型(类名称)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许为 null,可以设置它的required属性为false。(Autowired有多个类型会报错,除非加入了@Qualifier(“id/name”)做限制,或者这个属性的名称可以匹配到容器中的Id/name否则在IDEA编译时就报错)
- 可以标注在变量,也可以标注在set方法。
- 有一个布尔变量的 required 属性,用来决定在依赖注入时候是否检测依赖的 Bean 在 BeanFactory 里面是否存在,默认是 true。
@Qualifier("容器中的id/name")
,是用来消除依赖注入冲突的,当@Autowired有多个相同类型时就会报错,这是可以用@Qulifier/ˈkwɑːlɪfaɪər/做一个限定。
2.2扫描组件(context)
1
2
|
<!--开启扫描 已经包含<context:annotation-config/>这句启用注解 -->
<context:component-scan base-package="com.lx.*"></context:component-scan>
|
<mvc:annotation-driven />和 <context:annotation-config />区别
<mvc:annotation-driven /> 讲解
<mvc:annotation-driven /> 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的。
并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。
后面,我们处理响应ajax请求时,就使用到了对json的支持。
后面,对action写JUnit单元测试时,要从spring IOC容器中取DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,来完成测试,取的时候要知道是<mvc:annotation-driven />这一句注册的这两个bean。
<context:annotation-config />讲解
作用是式地向 Spring 容器注册
AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、
PersistenceAnnotationBeanPostProcessor 以及 RequiredAnnotationBeanPostProcessor 这 4 个BeanPostProcessor。
注册这4个 BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解
@ Resource 、@ PostConstruct、@ PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor
如果想使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessor的Bean。
如果想使用 @Required的注解,就必须声明RequiredAnnotationBeanPostProcessor的Bean。同样,传统的声明方式如下:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
一般来说,这些注解我们还是比较常用,尤其是Antowired的注解,在自动注入的时候更是经常使用,所以如果总是需要按照传统的方式一条一条配置显得有些繁琐和没有必要,于是spring给我们提供<context:annotation-config />的简化配置方式,自动帮你完成声明。
2.3Bean注解分类

接下来我们可以为要注册为Bean的加上如下几个注解。目前功能相同。
@Service用于标注业务层组件
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
为bean注入常见类型。可以作用在set方法上,相当于
1
2
|
@Value("lusenlin")
public String name;
|
@Scope(“singleton单例/prototype多例”)
3完全注解
我们可以写applicationContext.xml实现Spring,也可以完全的脱离它。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Configuration //相当于<beans>标签
//@ComponentScan("com.lx.*")+在包下的类上加@Component注解注册bean
//也可以按照下面的@Bean 注册
public class ApplicationConfig {
@Bean //相当于<bean>标签
public OracleImpl getOracleImpl(){ //这里相当于id=getOracleImpl
return new OracleImpl(); //相当于class=“”
}
}
-----------------测试---------------
//以class文件来配置的Spring
ApplicationContext context=new AnnotationConfigApplicationContext(ApplicationConfig.class);
OracleImpl dao= context.getBean("getOracleImpl",OracleImpl.class);
OracleImpl mydao1= context.getBean("getOracleImpl",OracleImpl.class);
System.out.println(dao==mydao1);//true
|
@Configuration //相当于标签
@ComponentScan(“com.lx.*")+在包下的类上加@Component注解注册bean
@Bean //相当于标签 默认id为getxxx,也可以自己指定id 需要在方法上写
@Import(xxx.class)相当于xml中导入其他的配置类
第四章-Aop
什么是AOP?
AOP(Aspect Oriented Programming)面向切面编程
AOP(这里的AOP指的是面向切面编程思想,而不是Spring AOP)主要的的实现技术主要有Spring AOP和AspectJ。
Aspectj: AspectJ的底层技术是静态代理,即用一种AspectJ支持的特定语言编写切面, 通过一个命令来编译,生成一个新的代理类,该代理类增强了业务类,这是在编译时增强,相对于下面说的运行时增强,编译时增强的性能更好。
Spring AOP:采用的是动态代理,在运行期间对业务方法进行增强,所以不会生成新类,对于动态代理技术, Spring AOP提供了对JDK动态代理的支持以及CGLib的支持。 JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被代理目标类的接口信息 (应用Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用实现了InvocationHandler接口的方法来处理。 CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成子类。把代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。 因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
但是Spring AOP基于注解配置的情况下,需要依赖于AspectJ包的标准注解,但是不需要额外的编译 以及AspectJ的织入器,而基于XML配置不需要。
1代理模式
为什么学习代理模式?这就是AOP的实现底层原理。
代理模式分类:
1.1静态代理
角色分析:
●抽象角色: 一般会使用接口或者抽象类来解决。出租
●真实角色:被代理的角色。 房东
●代理角色:代理真实角色,代理真实角色后,我们一般会做-一些附属操作。中介
●客户:访问代理对象的人!。
1
2
3
4
|
//抽象角色 就是把真实角色的需求做一个抽象类。 出租
public interface Rent {
void rentHouse();
}
|
1
2
3
4
5
6
|
//真实角色
public class House implements Rent {
@Override
public void rentHouse() {
System.out.println("前方300米处有房出租");
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
//代理角色 代理真实角色,可以增强真实角色的功能
public class MyProxy implements Rent {
private House house;
public MyProxy(House house) {
this.house = house;
}
@Override
public void rentHouse() {
house.rentHouse();
System.out.println("需要的快来找我孙红雷");
}
}
|
1
2
3
4
5
|
House house=new House();
MyProxy proxy=new MyProxy(house);
proxy.rentHouse();
//前方300米处有房出租
//需要的快来找我孙红雷 代理角色对租房行为提供了增强
|
优点:可以把公共的业务交给代理类完成,让真实角色的功能更加纯粹,实现了业务的分工,当公共需求更改时候,只需要改动代理类就可以了。
缺点:我们每对一个真实角色实行增强,都需要再创建一个代理类,导致类迅速增多,代码量翻倍开发效率变低。
1.2动态代理
●动态代理和静态代理角色一样
●动态代理的代理类是动态生成的,不是我们直接写好的!
●Spring AOP动态代理分为两大类:基于接口的动态代理,基于类的动态代理。
基于接口— jDK动态代理。(接下来所描述的。缺点是必须有接口)只能对实现了接口的类生成代理,而不能针对类。
基于类: cglib。把代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。 因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
需要了解两个类:Proxy、InvocationHandler。
Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
- 1用哪个类加载器去加载代理对象,
2用被代理的对象的类获得动态代理类需要实现的接口
3实现了InVocationHandler类的实例 :动态代理方法在执行时,会调用h里面的invoke方法去执行
InvocationHandler用来为特定的对象增强方法的功能。
个人理解:Proxy用前两个参数,类加载器和,接口创建了代理类,用第三个参数,实现了把代理类的方法进行增强后做了返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
//用这个实现了InvocationHandler的类去生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理对象的对象
public Object obj;
public ProxyInvocationHandler(Object obj) {
this.obj = obj;
}
//生成并且获得代理类 需要三个参数,
// 1用哪个类加载器去加载代理对象,
// 2用被代理的对象的类获得动态代理类需要实现的接口
// 3实现了InVocationHandler类的实例 :动态代理方法在执行时,会调用h里面的invoke方法去执行
public Object getProxy() {
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
}
//处理代理的实例,并且返回
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1参数是生成的代理类 2是被增强的方法 3被增强的方法所需要的参数
System.out.println("hello");
Object object= method.invoke(obj,args);
System.out.println("world");
return object;
}
}
|
2AOP
AOP(Aspect Oriented Programming)面向切面编程
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
2.1专业术语
target
目标类:需要被代理的类 比如xxDaoImpl
Joinpoint(连接点)
指的那些可能被拦截到的方法(就是被代理对象的接口中的所有方法)
PointCat切入点
被增强的连接点(连接点有多个,但真正切入的点可能只是选取连接点中的一部分点)
advice通知/增强
拦截到Joinpoint后要做的事情就是通知,分为:前置通知、后置通知、异常通知、最终通知(finally)、环绕通知(切面要完成的功能)
Weaving织入
把增强应用到目标对象来创建新的代理对象的过程,把advice和targer结合起来
Proxy代理
一个类被AOP织入增强后,产生一个结果代理类
Aspect切面
是切入点PointCat和通知advice的结合
Introduction(引介) :
引介是一种特殊的通知在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加些方法或Field。
2.2通知类
advice常见通知类:MethodBeforeAdvice前置通知类、AfterReturningAdvice后置通知类、MethodInterceptor环绕通知
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//前置通知类
@Component("beforeAdvice")
public class MyLog implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
//执行方法前增强
System.out.println(target.getClass().getName()+"类的"+method.getName()+" ==是在Mylog中被增强的");
}
}
//环绕通知类
public class LogArroundAdvice implements MethodInterceptor{
private Logger logger = Logger.getLogger(this.getClass().getName());
public Object invoke(MethodInvocation arg0) throws Throwable {
// 在方法前后
logger.log(Level.INFO,"方法前后都执行 =LogArroundAdvice="+arg0.getMethod().getName());
Object obj=arg0.proceed();//执行目标方法
logger.log(Level.INFO,"方法前后都执行 =LogArroundAdvice="+arg0.getMethod().getName()+"返回值"+obj);
return obj;
}
}
|
2.3SpringAPI接口实现
1
2
3
4
5
6
|
使用AOP织入,需要导入jar包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
|
1
2
3
4
5
6
7
8
|
<aop:config>
<!--切入点 定义 expression表达式 (..)表示所有方法-->
<aop:pointcut id="mypoi" expression="execution(* com.lx.springproxy.UserServiceImpl.*(..))" />
<!-- 增强定义,需要有实现了Spring增强接口的类 和切入点 -->
<aop:advisor advice-ref="beforeAdvice" pointcut-ref="mypoi" />
<aop:advisor advice-ref="afterAdvice" pointcut-ref="mypoi" />
</aop:config>
|
2.4自定义实现AOP
自定义实现AOP,不需要再通过接口去实现了。
1
2
3
4
5
6
7
8
9
10
11
|
<!--自定义实现代理-->
<aop:config >
<!--自定义切面 ref要引用的自定义类-->
<aop:aspect ref="diyPointcat">
<aop:pointcut id="po1" expression="execution(* com.lx.springproxy.UserServiceImpl.*(..))"/>
<aop:after method="after" pointcut-ref="po1"></aop:after>最终通知
<aop:before method="before" pointcut-ref="po1"></aop:before>前置通知
<aop:after-returning method="" pointcut-ref="po1"></aop:after-returning>后置通知
<aop:after-throwing method="" pointcut-ref="po1"></aop:after-throwing>异常通知
<aop:around method="aroundMethod" pointcut-ref="po1"></aop:after-throwing>环绕通知
</aop:aspect>
|
环绕通知这一点有些不一样。
1
2
3
4
5
6
7
8
9
10
|
//Spring框架为我们提供了一个接口: ProceedingJoinPointo 该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
//该接口可以作为环绕通知的方法参数,在程序执行时,spring框架 会为我们提供该接口的实现类供我们使用。
public object aroundPringLog(ProceedingJoinPoint pjp){
object rtValue = null ;
try{
Object[] args = pjp. getArgs();//得到方法执行所需的参数
System. out . println("Logger类中的aroundPringlog方法开始记录日志了。。。前置");
rtValue = pjp . proceed(args);//明确调用业务层方法(切入点方法)
//这个方法前就是前置,异常就是异常,finall就是最终
}
|
2.5注解实现AOP(暂略)
3事务
3.1事务及其有关概念
特性:把一组业务当做一个业务执行,要么都成功,要么都失败。确保数据的完整性和一致性。
读数据不需要或只为其指定只读事务,而数据的插入,修改,删除就需要事务管理了。
3.2Spring配置事务方式
根据代理机制的不同,Spring事务的配置又有几种不同的方式:
第一种方式:每个Bean都有一个代理
第二种方式:所有Bean共享一个代理基类
第三种方式:使用拦截器
第四种方式:使用tx标签配置的拦截器
第五种方式:全注解
注意:事务管理器依赖于sessionFactory,需要有tx的命名空间。或通过基于@Transactional注解的方式
声明式事务:基于SpringAOP方式,也是常用方式。
编程式事务:改变了原有代码,所以一般不会这样做。
第三种方式:使用拦截器

第四种方式:使用tx标签配置的拦截器:propagationˌ[prɑːpəˈɡeɪʃn]传播,事务传播方式,默认为REQUIRED必须的,如果已经存在一个事务中,加入到这个事务中 如果当前没有事务,就创建一个。

第五种方式:全注解
1
2
3
4
5
6
7
8
9
|
<!-- 1创建事务管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 开启事务注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true"/>
|
3.3事务传播类型
事务传播行为类型 |
说明 |
REQUIRED |
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
SUPPORTS |
支持当前事务,如果当前没有事务,就以非事务方式执行。 |
MANDATORY |
使用当前的事务,如果当前没有事务,就抛出异常。 |
REQUIRES_NEW |
新建事务,如果当前存在事务,把当前事务挂起。 |
NOT_SUPPORTED |
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
NEVER |
以非事务方式执行,如果当前存在事务,则抛出异常。 |
NESTED |
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类 似的操作。 |
第五章-整合
2SSM框架整合
2.1pom.xml依赖
注意依赖版本号和项目名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lx</groupId>
<artifactId>ssmbuild</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>ssmbuild Maven Webapp</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!--Servlet - JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
</dependencies>
<build>
<!--Maven资源过滤设置-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
|
2.2web.xml配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<!-- springMVC -->
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--encodingFilter-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring 在web文件中配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 加入Spring的监听-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--Session过期时间-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>
|
2.3xml配置书写

applicationContext.xml包含三个spring-dao、spring-mvc、spring-service
总:applicationContext
1
2
3
4
5
6
7
8
9
10
|
<?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">
<import resource="spring-dao.xml"/>
<import resource="spring-service.xml"/>
<import resource="spring-mvc.xml"/>
</beans>
|
1spring-dao
数据库文件使用配置文件database.properties
**注意:**dao接口的名称可能不同。
1
2
3
4
5
|
jdbc.driver=com.mysql.jdbc.Driver
#Mysql8.0需要加上url而且需要更换数据库驱动 &serverTimezone=Asia/shanghai
jdbc.url=jdbc:mysql://localhost:3306/store_ssm_vue?useSSL=false&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
|
spring-dao.xml
若有多个配置文件写法如下;
1
|
<context:property-placeholder location="classpath*:redis.properties,classpath*:database.properties"/>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置整合mybatis -->
<!-- 1.关联数据库文件 -->
<context:property-placeholder location="classpath:database.properties"/>
<!-- 2.数据库连接池 -->
<!--数据库连接池
dbcp 半自动化操作 不能自动连接
c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)
druid
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性 -->
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 10s-->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
<!--最大空闲时间,3600秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->
<property name="maxIdleTime" value="7200"/>
<!--每120秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="120"/>
</bean>
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--也可以不配置MyBatis全局配置文件,再这里说明-->
<property name="mapperLocations" value="classpath:com/lsl/mapper/xml/*.xml"></property>
<property name="typeAliasesPackage" value="com.lsl.entity"></property>
</bean>
<!-- 4.配置扫描Dao接口包,动态实现Dao接口注入到spring容器中 -->
<!--解释 : https://www.cnblogs.com/jpfss/p/7799806.html-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="com.lsl.mapper"/>
</bean>
</beans>
|
mybatis-config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置数据源,交给spring去做-->
<typeAliases>
<!--<package name="com.lsl.entity"/>-->
</typeAliases>
<mappers>
<!--<mapper resource="com/lsl/mapper/xml/EmployeeMapper.xml"/>-->
</mappers>
</configuration>
|
2spring-mvc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置SpringMVC -->
<!-- 1.开启SpringMVC注解驱动 -->
<mvc:annotation-driven />
<!-- 2.静态资源默认servlet配置-->
<mvc:default-servlet-handler/>
<!-- 3.配置jsp 显示ViewResolver视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 4.扫描web相关的bean -->
<context:component-scan base-package="com.lx.controller" />
</beans>
|
3spring-service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 扫描service相关的bean -->
<context:component-scan base-package="com.lsl.service" />
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启事务注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true"/>
</beans>
|
常见知识点
-
BeanFactory和ApplicationContext的区别
●ApplicationContext 是现在使用的工厂
ApplicationContext context = new
ClassPathxmlApplicat ionC ontext (” applicationContext. xm1”);
●XmIBeanFactory是老版本使用的工厂,目前已经被废弃[了解]
BeanF actory beanFactory = new XmlBeanF actory(new
ClassPathResource(“applicationContext. xm1”));
两者的区别:
ApplicationContext加载方式是框架启动时就开始创建所有单例的bean,存到了容器里面
BeanFactory加载方式是用到bean时再加载(目前已经被废弃)
-
构造方法注入和设值注入有什么区别
唯一的区别在于2种方式创建合作者的顺序不同。一般把一个Bean设计为构造函数接收依赖对象时,其实表达了2个对象间的一种强的聚合关系:组合关系。就比如一辆车如果没有轮子、引擎等部件那么车也就不存在了。
如果你的应用中有这样类似的场景那么你应该使用“构造函数注 入”的方式管理他们的关系。“构造函数注入”可以保证合作者先创建,在后再创建自己。若是此时采用设值注入,而忘记设置某个值,这个值为Null,若没注意到这一点,那就等着改BUG吧。
通过set方法注入的方式表达了2个对象间较弱的依赖关系:聚合关系。就像一辆车,如果没有车内音像车也时可以工作的。当你不要求合作者于自己被创建 时,“set方法注入”注入比较合适。
使用构造函数依赖注入时,Spring保证所有一个对象所有依赖的对象先实例化后,才实例化这个对象。(没有他们就没有我原则)
使用set方法依赖注入时,Spring首先实例化对象,然后才实例化所有依赖的对象。
-
知识点1 ApplicationContext
ClassPathXmlApplicationContext基于xm|方式(配置文件在resource下)
FileSystemXmlApplicationContext基于xml方式(配置文件路径随意)
AnnotationConfigApplicationContext基于注解方式
-
知识点2 bean的作用范围和生命周期
●单例对象: scope-“singleton”
一个应用只有一个对象的实例。它的作用范围就是整个引用。
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象- -直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
●多例对象: scope="prototype”
每次访问对象时,都会重新创建对象实例。
生命周期:
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就-直活着。
对象死亡:当对象长时间不用时,被java的垃圾回收器回收了.
1Spring中的事件管理
Spring提供了事件的发布和订阅,可以使核心业务与子业务进行解耦,也便于后期的业务的扩展。比如用户登录动作,用户登录需要记录登录信息,可增加一个监听事件处理即可,后续可能会增加异地登录通知功能,新增一个监听事件来做就好,不需要修改登录业务。
(1)自定义Event类,实现ApplicationEvent定义事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package com.lx.service.impl;
import org.springframework.context.ApplicationEvent;
public class UserRegisterEvent extends ApplicationEvent {
//事件定义:Object是传入的对象
//ApplicationContext 通过 ApplicationEvent 类和 ApplicationListener 接口进行事件处理。
// 如果将实现 ApplicationListener 接口的 bean 注入到上下文中(注入到spring中),
// 则每次使用 ApplicationContext 发布 ApplicationEvent 时,
// 都会通知ApplicationListener 接口的 bean。本质上,这是标准的观察者设计模式。
public UserRegisterEvent(Object source) {
super(source);
}
}
|
(2)调用ApplicationEventPublisher的publishEvent方法发布事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package com.lx.service.impl;
import com.lx.entity.User;
import com.lx.mapper.UserMapper;
import com.lx.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
/* 服务实现类 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService, ApplicationEventPublisherAware {
//事件发布者 ApplicationEventPublisher对象
//方式一:用@Autowire或者@Resource获得
private ApplicationEventPublisher applicationEventPublisher;
//方式二:用Aware接口获得,然后赋值后给get方法
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
System.out.println("UserServiceImpl 我通过Aware获得了 Application的ApplicationEventPublisher接口对象");
this.applicationEventPublisher = applicationEventPublisher;
}
public ApplicationEventPublisher getApplicationEventPublisher() {
return applicationEventPublisher;
}
}
|
(3)自定义监听类(方法上加注解@EventListener监听发布的事件也可以)
1
2
3
4
5
6
7
|
//事件订阅者(事件监听)
@Component
public class EmailService implements ApplicationListener<UserRegisterEvent> {
@Override
public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
System.out.println("邮件服务接到通知,给 " + userRegisterEvent.getSource() + " 发送邮件...");
}
|
(4)测试类中使用,实际可以在Controller中调用
1
2
3
4
5
6
7
8
|
//事件监听
@Test
public void applicationListenTest(){
System.out.println("=======================================分割线===================================");
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserServiceImpl userServiceImpl= (UserServiceImpl) context.getBean("userServiceImpl");
userServiceImpl.getApplicationEventPublisher().publishEvent(new UserRegisterEvent("你好我是Lusenlin"));
}
|
2BeanFactory和FactoryBean
BeanFactory:是IOC容器的顶级父类接口,ApplicationContext就是这个接口的子类,它是一个生产和管理Bean的一个工厂。BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等。
原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口,它由BeanFactory接口派生而来,
ApplicationContext包含BeanFactory的所有功能,通常建议比BeanFactory优先
ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:
• MessageSource, 提供国际化的消息访问
• 资源访问,如URL和文件
• 事件传播
• 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层;
FactoryBean:当我们使用标签去容器中注册bean时,需要指定属性等,若对象的创建比较复杂,属性比较多时,在xml中配置就显得臃肿,这时可以使用org.springframework.bean.FactoryBean的工厂接口,用户可以通过实现该接口定制实例化的bean。
T getObejct()
: 返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中实例缓存池中。
boolean isSingleton()
:返回有FactoryBean创建的bean的实例的作用域是singleton还是prototype,这里默认返回的是true,也就是默认是singleton bean。
Class getObjectType()
: 返回FactoryBean创建的 bean的类型。
3refresh方法