什么是Spring
Spring简介
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
- Spring 是一个开源的框架,为了解决企业应用开发的复杂性而创建的
- spring是一个轻量级的控制反转(Ioc)和面向切面(AOP)的容器框架
- 从大小和开销两个方面而言spirng是轻量级的
- 通过控制反转(Ioc)的技术达到松耦合的目的
- 提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发
- 包含并且管理应用对象的配置和生命周期,这个意义上是一种容器
- 将简单的组件配置,组合成为复杂的应用,这个意义上是框架
目的:解决企业应用开发的复杂性
优点:
- Spring是一个开源免费的框架(容器)
- Spring是一个轻量级的框架,非侵入式的
- 控制反转 IoC,面向切面 AOP
- 对事物的支持,对框架的支持
组成
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式。
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
-
核心容器
提供 Spring 框架的基本功能。
核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IoC)将应用程序的配置和依赖性规范与实际的应用程序代码分开。 -
Spring 上下文
Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息,包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。 -
Spring AOP
Spring在它的AOP模块中提供了对面向切面编程的丰富支持。AOP允许通过分离应用的业务逻辑与系统级服务(例如安全和事务管理)进行内聚性的开发。 -
Spring DAO
该模块对现有的JDBC技术进行了优化。可以保持数据库访问代码干净简洁,并能防止因关闭数据库资源失败而引起的问题。 -
Spring ORM
Spring并没有自己实现ORM框架,只是集成了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。 -
Spring Web 模块
Web上下文模块建立于应用上下文模块之上,提供了一个适合于Web应用的上下文。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。 -
Spring MVC 框架
Spring为构建Web应用提供了一个功能全面的MVC框架。虽然Spring可以很容易地与其它MVC框架集成,例如Struts2,但Spring的MVC框架使用IoC对控制逻辑和业务对象提供了完全的分离。
控制反转 IoC
IoC理论推导
用我们原来的方式写一段代码
#1. UserDao接口
public interface UserDao {
public void getUser();
}
#2、Dao的实现类
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户数据");
}
}
#3. UserService的接口
public interface UserService {
public void getUser();
}
#4. Service的实现类
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
#5. 测试
@Test
public void test(){
UserService service = new UserServiceImpl();
service.getUser();
}
现在修改一下:
# 把Userdao的实现类增加一个
public class UserDaoMySqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据");
}
}
# 使用MySql需要去service实现类里修改对应的实现
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoMySqlImpl(); // 修改对应的实现
@Override
public void getUser() {
userDao.getUser();
}
}
# 再增加一个Userdao的实现类,若我们要使用Oracle,又需要去service实现类里面修改对应的实现
public class UserDaoOracleImpl implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle获取用户数据");
}
}
现在程序的耦合性太高了, 牵一发而动全身。
如何解决:利用set
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set实现
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
# 测试
@Test
public void test(){
UserServiceImpl service = new UserServiceImpl();
service.setUserDao( new UserDaoMySqlImpl() );
service.getUser();
//又想用Oracle
service.setUserDao( new UserDaoOracleImpl() );
service.getUser();
}
以前所有东西都是由程序去进行控制创建,而现在是由我们自行控制对象的创建,程序只负责提供一个接口。这种思想让程序员更多的去关注业务的实现,让程序耦合性大大降低,这也就是IoC的原型。
IoC 和 DI
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,它是由主动的编程变成被动的接收。
IoC (Inversion of Control)是 Spring 的一种设计思想
在传统的程序设计,我们直接在对象内部通过 new 来创建对象,是程序主动去创建依赖对象;而在 Spring 中有专门的一个容器来创建和管理这些对象,并将对象依赖的其他对象注入到该对象中,这个容器我们一般称为 IoC 容器。所有的类的创建、销毁都由 Spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 Spring,所以这叫控制反转。
DI(Dependency Injection)依赖注入
依赖注入是指组件之间的依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(DI)。
bean
在 Spring 中,构成应用程序主干并由 Spring IoC 容器管理的对象称为 bean。 bean 是由 Spring IoC 容器实例化,组装和管理的对象。
bean 可以认为是那些我们想注入到 Spring IoC 容器的 Java 对象实例的抽象。
项目中我们经常会在 Service 上使用 @Service 注解,然后在要使用该 Service 的类中通过 @Autowire 注解来注入,这个 Service 就是一个 bean。
@Service 注解相当于告诉 IoC 容器:这个类你需要帮我创建和管理;而 @Autowire 注解相当于告诉 IoC 容器:我需要依赖这个类,你需要帮我注入进来。
依赖注入(DI)
- 依赖 : 指Bean对象的创建依赖于容器;Bean对象的依赖资源
- 注入 : 指Bean对象所依赖的资源,由容器来设置和装配
依赖注入是利用set方法来进行注入的:
Hello实体类
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("Hello,"+ name );
}
}
编写spring文件,命名为beans.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">
<!--bean就是java对象,由Spring创建和管理-->
<bean id="hello" class="com.ldc.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
测试
@Test
public void test(){
//解析beans.xml文件,生成管理相应的Bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//getBean : 参数即为spring配置文件中bean的id .
Hello hello = (Hello) context.getBean("hello");
hello.show();
}
面向切面编程 AOP
AOP(Aspect Oriented Programming)
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP 与 OOP 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角。在 OOP 中以类(class)作为基本单元, 而 AOP 中的基本单元是 Aspect(切面)。
AOP在Spring中提供声明式事务,同时允许用户自定义切面。
为什么需要 AOP
场景:开发中在多个模块间有某段重复的代码,我们怎么处理的?
在传统的面向过程编程中,我们将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法。然而需求总是变化的,需要我们一直做修改。
提出一个公共方法,每个接口都来调用这个接口。
将方法注入到接口调用的地方(切点)。
实际上涉及到多个地方具有相同的修改问题都可以通过 AOP 来解决。
AOP术语
AOP 领域中的特性术语:
-
横切关注点:跨越应用程序多个模块的方法或功能。与业务逻辑无关,但是需要我们关注的部分,如日志、安全、事务等等....
-
切面(ASPECT):横切关注点被模块化的特殊对象(是一个类)
-
通知(Advice):切面必须要完成的工作(是类中的一个方法)
-
目标(Target):被通知对象
-
代理(Proxy):向目标对象应用通知之后创建的对象
-
切入点(PointCut):切面通知执行的“地点”
-
连接点(JointPoint):与切入点匹配的执行点
-
织入(Weaving):将 aspect 和其他对象连接起来, 并创建 adviced object 的过程
AOP的实现
- 通过 Spring API 实现
- 通过自定义类来实现
- 使用注解实现
使用注解实现
编写一个注解实现的增强类:
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
在Spring配置文件中,注册bean,并增加支持注解的配置:
<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.ldc.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>