浅析Spring
一、Spring简介
Spring 框架是一个开源的 轻量级的企业级 Java 应用程序开发框架。
Spring框架的两大核心:IOC/DI与AOP。
下面是Spring框架的重要模块:
二、Spring IOC(控制反转)
2.1、什么是IOC?
控制反转,是一种设计思想,由spring来管理应用中所有对象的创建和对象的生命周期。
特点:降低了类与类之间的耦合度(解耦)。
2.2、IOC容器的种类
BeanFactory
这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactor 中被定义。BeanFactory 和相关的接口,比如BeanFactoryAware、DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。
在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。
在资源宝贵的移动设备或者基于 applet 的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext,除非你有更好的理由选择 BeanFactory。
Application Context容器
Application Context 是 BeanFactory 的子接口,也被成为 Spring 上下文。
Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。
ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。
最常被使用的 ApplicationContext 接口实现:
- FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
- ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
- WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
2.3、什么是Bean
被IOC容器管理的对象就称之为Bean
2.4、Bean的初始化方式
构造函数初始化:使用类的构造器实例化;
静态工厂初始化和实例工厂初始化:间接通过类构造器实例化。
2.5、Bean的作用域
-
singleton
单例模式,在IOC容器中仅存在一个实例
-
prototype
多例,每次从IOC容器调用Bean时,都会返回一个新的实例
-
request
每次Http请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
-
session
同一个会话共享一个Bean,不同的会话使用不同的Bean,仅适用于WebApplicationContext环境
-
application
一般用于portlet应用环境,该作用域仅适用于WebApplicationContext环境
三、Spring DI(依赖注入)
依赖注入是处理IOC容器里的类与类之间的依赖关系。
依赖注入就是通过IOC容器将类之间的关系在容器内部绑定,使得类与类之间进一步解耦,让类更加专注于业务本身而不用处理其他对象的生命周期。无论是IOC或者是DI其实都是为了解耦,前者是为了将类的生命周期交给IOC容器统一管理,后者处理类与类的关系,而这些动作都将在容器内完成。
3.1、注入的方式
Set方法注入、构造方法注入、接口注入
注:接口注入模式因为历史较为悠久,在很多容器中都已经得到应用。但由于其在灵活性、易用性上不如其他两种注入模式,因而已经退出舞台。
3.2、数据注入
list、map、set、props
null与空值
p-namespace
c-namespace
3.3、懒加载
lazy-init="true"
3.4、自动装配
no(默认):不自动装配
byName:根据名称来自动装配
byType:根据类型来自动装配
constructor:使用构造方法来自动装配
autowire-candidate:为false表示该类不参于自动装配。例如一个接口2个实现,那么自动装配就不知道到底用哪个实现去装配了,此时将其中一个设置autowire-candidate属性为flase,表示该实现类不参与自动装配。
四、SpringAOP(面向切面编程)
4.1、什么是AOP?
面向切面的编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象的编程(OOP)。OOP中模块化的关键单元是类,而在AOP中模块化是切面。切面使关注点(例如事务管理)的模块化可以跨越多种类型和对象。
Spring的关键组件之一是AOP框架。尽管Spring IoC容器不依赖于AOP(这意味着您不需要使用AOP),但AOP是对Spring IoC的补充,以提供功能强大的中间件解决方案。
AOP在Spring框架中用于:
- 提供声明式企业服务。最重要的此类服务是 声明式事务管理。
- 让用户实现自定义方面,并用AOP补充其对OOP的使用。
4.2、面向切面组成的部分
切面:即你要切入的模块代码
切入点:模块要切入的地方、要切入的地点
通知:切入模块的运行时机
4.3、spring aop通知的种类
前置通知:before
后置通知:after
环绕通知:around
异常通知:throwing
返回通知:returning
4.4、Spring AOP原理之代理模式
Spring AOP使用JDK动态代理或CGLIB创建给定目标对象的代理。JDK动态代理内置在JDK中,而CGLIB是常见的开源类定义库(重新打包为spring-core
)。
如果要代理的目标对象实现至少一个接口,则使用JDK动态代理。代理了由目标类型实现的所有接口。如果目标对象未实现任何接口,则将创建CGLIB代理。
4.4.1、静态代理
静态代理即代理模式。
实现方式:
代理类中调用被代理类的方法。
4.4.2、动态代理
动态代理指的是jdk中的动态代理。
实现方式:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("这是动态代理在调用方法之前做的逻辑");
Object invoke = method.invoke(object, args);
System.out.println("这是动态代理在调用方法之后做的逻辑");
return invoke;
}
}
4.4.3、cglib代理
CGLib是一个强大的, 高性能的代码生成库. 被广泛应用于 AOP 框架. 用以提供方法拦截操作.
CGLib采用底层的字节码技术, 可以为一个类创建子类, 在子类中采用方法拦截的技术拦截所有父类方法的调用, 并织入横切逻辑
1、创建cglib代理类,代理类需要实现MethodInterceptor接口并重写intercept方法
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("之前插入的逻辑");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("之后执行的逻辑");
return o1;
}
}
2、创建目标类
3、编写测试类,创建enhancer类,设置超类和回调对象,然后创建对象。
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(User.class);
enhancer.setCallback(new CglibProxy());
User user = (User) enhancer.create();
user.say();
spring中强制使用cglib的方法:
<aop:aspectj-autoproxy proxy-target-class="true"/>
4.5、Spring事务传播特性
required:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择
supports:支持当前事务,如果当前没有事务,就以非事务方式执行。
mandatory:支持当前事务,如果当前没有事务,就抛出异常。
requires_new:新建事务,如果当前存在事务,把当前事务挂起。
not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
never:以非事务方式执行,如果当前存在事务,则抛出异常。
nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与propagation_required类似的操作。
4.6、事务的三种实现方式
1、硬编码事务
传统事务管理方式,需要自己手动提交回滚事务。
2、声明式事务
使用spring aop来声明事务
3、注解式事务
使用注解来使用事务
五、注解
@Controller
作用在Controller上,等同于<bean id="xx" class="xxx">
@Service
作用在service层,等同于<bean id="xx" class="xxx">
@Repository
作用在dao层,等同于<bean id="xx" class="xxx">
@Component
作用在普通类,等同于<bean id="xx" class="xxx">
以上几个注解需要配合<context:component-scanbase-package=”XXX”/>使用
@Autowired
默认先按byType,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常。
可以手动指定按byName方式注入,使用@Qualifier。
如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) 。
@Resource
默认按 byName自动注入,如果找不到再按byType找bean,如果还是找不到则抛异常,无论按byName还是byType如果找到多个,则抛异常。
可以手动指定bean,它有2个属性分别是name和type,使用name属性,则使用byName的自动注入,而使用type属性时则使用byType自动注入。
@Resource(name=”bean名字”)
或
@Resource(type=”bean的class”)
@Inject
使用@Inject需要引用javax.inject.jar,它与Spring没有关系,是jsr330规范。
与@Autowired有互换性。
@Scope
配置Bean的作用域
@Singleton
只要在类上加上这个注解,就可以实现一个单例类,不需要自己手动编写单例实现类。
@Value
用于将属性文件中的值注入到实体中