认识Spring框架
Spring框架是Java应用最广的一个框架,它的成功来源于它的理念,并非它技术本身,其中包括 IOC(Inversion of Control, 控制反转)和AOP(Aspect Oriented Programming,面向切面编程).
什么是Spring
1.Spring是一个轻量级的DI/IOC和AOP容器的开源框架, 来源于Rod Johnson的著作**《Expert one on one J2EE design and development》**中阐述的理念延伸而来。
2.Spring提倡"以少入侵”的方式来管理代码,这表示我们可以随时安装或者卸载它。
- 适用范围:一切Java应用
- Spring的根本作用:简化Java应用开发
Spring中的常用术语
-
框架:能够完成一定功能的半成品。
框架能够帮助我们构建项目的整体框架,完成一些基础功能,例如类的创建以及类与类之间的协作,能够大大简化我们的开发。
-
非入侵式设计:
从框架的角度可以理解为:无需继承框架的任何类
这样我们在更换一个框架时,之前写的代码几乎可以完美使用。
-
轻量级和重量级
轻量级一般就是指非入侵式的,所依赖的东西非常少,占用的资源也非常少、部署也十分简单。
-
JavaBean:
即符合JavaBean规范的Java类。
-
POJO
Plain Old Java Objects, 简单老式的Java对象
可以包含业务逻辑或十九华逻辑,但不担当任何特殊角色且不继承或不实现任何其他Java框架的类或者接口
注:bean的各种名称——虽然Spring用bean或者Javabean来表示其应用组件,但是不意味着Spring必须遵从Javabean规范,一个Spring组建可以是任意形式的POJO。
-
容器:
顾名思义,在生活中是盛放东西的器具,从程序设计角度看,就是装对象的对象,因为存在存放、删除(拿出)等操作,所以容器还要管理对象的生命周期。
Spring的优势
- 根据配置文件创建以及组装对象之间的依赖关系。
- AOP可以帮助我们无耦合的实现日志记录,性能统计,安全控制等等。
- 简化了数据库事务的管理。
- 提供了很多第三方数据访问框架,自己也提供了一套JDBC访问模板来方便数据库的访问。
- 提供了与第三方web框架的无缝集成,自己也提供了Spring MVC框架,来方便管理web框架搭建。
- 与Java EE整合,与很多其他技术整合。
Spring基本框架结构
- Data Access Integration(数据访问集成)层包含了JDBC、ORM、OXM、JMS、Transactions模块
- Web(网络)层包含了Web、Servlet、Porlet、Struts模块
- AOP(面向切面编程)提供了符合AOP联盟标准的面向切面编程的实现。
- Core Contanier(核心容器)包含了Beans、Core、Context、Expression Language模块
- Test(测试)模块支持使用JUnit和TestNG对Spring组件进行测试
IOC(Inverse Of Control)和DI(Dependency Injection)简介
IOC:Inverse Of Control(控制反转)
- 实际上为“反转控制可能更好理解”,并非是一种技术,而是一种编程思想,就是将原来在编程者手中的创建对象的控制权,转交给Spring框架来完成。
- 正控:若要使用某个对象,就需要自己去创建这个对象
- 反控:若要使用某个对象,只需要从Spring容器中进行获取,而不用操心对象的创建过程,也就是把对象的创建反转Spring框架
- 好莱坞法则:Don’t call me, I’ll call you
Example
控制反转显然是一个抽象的概念,我们现在来举个例子
在以前,方便面和外卖还没有普及的时候,自己想吃东西,我们的第一反应就是自己去做,例如你想吃水果捞,你就要买水果,买酸奶,然后自己去做。注意,这些过程,都是你自己“主动”去创造的过程,也就是说你想吃水果捞,从头到尾你都要自己做。
然而,到了现在这个外卖盛行的年代,当你想吃什么东西的时候,第一反应都是打开“美团”或者“饿了么”看有没有自己想吃的东西,有的话就下单让他送过来。 请注意这个过程,在这个过程中,你并没有自己主动去创造,而是将“做水果捞”这个过程交给了商家去做,也就是你将“创造水果捞”的控制权“反转”给了店家。
编写第一个Spring程序(IntelliJ IDEA为例)
- 新建一个spring项目,命名为【spring】
- 在【POJO】包下新建一个【Source】类
package POJO;
public class Source {
private String fruit;//水果
private String taste;//口味
private String size;//大小
public String getFruit() {
return fruit;
}
public void setFruit(String fruit) {
this.fruit = fruit;
}
public String getTaste() {
return taste;
}
public void setTaste(String taste) {
this.taste = taste;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
}
- 在【src】目录下新建一个【applicationContext.xml】文件,通过该文件配置装配我们的bean
<?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 name="source" class="pojo.Source">
<property name="fruit" value="西瓜"/>
<property name="taste" value="草莓味"/>
<property name="size" value="大份"/>
</bean>
</beans>
- 在【test】Package下新建一个【TestSpring】类并进行测试
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Source;
public class TestSpring {
public static void test(){
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"applicationContext.xml"}
);
Source source = (Source) context.getBean("source");
System.out.println(source.getFruit());
System.out.println(source.getTaste());
System.out.println(source.getSize());
}
public static void main(String[] args) {
test();
}
}
总结
- 传统的方式:通过new关键字主动创建对象
- IOC方式:对象的生命周期由Spring掌控,直接从Spring获取一个对象。
DI:Dependency Injection(依赖注入)
- 指在Spring创建对象的过程中,将对象依赖属性通过配置赋值给该对象。
继续上面的例子
- 在【pojo】下创建一个FoodMaker类
package pojo;
public class FoodtMaker {
//此处关联了一个Source对象
private Source source = null;
public Source getSource() {
return source;
}
public void setSource(Source source) {
this.source = source;
}
public String makeFruit(){
String food = ("你点了一份" + source.getFruit() + source.getTaste() +source.getSize());
return food;
}
}
- 在xml文件中配置FoodMaker对象
- 注意,这里使用ref来注入对象
<?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 name="source" class="pojo.Source">
<property name="fruit" value="西瓜"/>
<property name="taste" value="草莓味"/>
<property name="size" value="大份"/>
</bean>
<bean name="foodMaker" class="pojo.FoodMaker">
<property name="source" ref="source"/>
</bean>
</beans>
- 在TestSpring中进行测试
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.FoodMaker;
import pojo.Source;
public class TestSpring {
public static void test(){
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"applicationContext.xml"}
);
Source source = (Source) context.getBean("source");
System.out.println(source.getFruit());
System.out.println(source.getTaste());
System.out.println(source.getSize());
FoodMaker foodMaker = (FoodMaker)context.getBean("foodMaker");
System.out.println(foodMaker.makeFood());
}
public static void main(String[] args) {
test();
}
}
- 运行结果如下:
总结
- IOC和DI其实是一个概念的不同描述,DI相对于IOC而言,明确描述了“被注入对象依赖IOC容器配置依赖对象”
Spring AOP
如果说IOC是Spring的核心,那么AOP就是Spring最为重要的功能之一,它在数据库事务中被广泛使用。
AOP 即 Aspect Oriented Program 面向切面编程
首先,在面向切面编程的思想里,把功能分为核心业务功能和周边功能。
- 核心业务:登录,增加数据,删除数据等等
- 周边功能:性能统计,日志,事务管理等等
周边功能在Spring面向切面编程AOP思想,即被定义成切面
在AOP的思想里,核心业务功能和切面功能分别独立开发,然后把切面功能和核心业务功能“组合”在一起,这就是AOP
AOP的目的
AOP可以将于业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、入职管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展和可维护性。
AOP中的概念
-
切入点(Pointcut)
在哪些类,哪些方法上切入(where)
-
通知(advice)
在方法执行的什么时间点(when:方法前、后、前后)做什么(what:增强的功能)
-
切面(Aspect)
切面 = 切入点 + 通知,就是:在什么时机,什么地方,做什么增强。
-
织入(Weaving)
把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)
AOP编程举例
- 在 package【service】下新建一个【ProductService】类
package service;
public class ProductService {
public void doSomeService(){
System.out.println("do some service!");
}
}
- 在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 name="source" class="pojo.Source">
<property name="fruit" value="西瓜"/>
<property name="taste" value="草莓味"/>
<property name="size" value="大份"/>
</bean>
<bean name="foodMaker" class="pojo.FoodMaker">
<property name="source" ref="source"/>
</bean>
<bean name="productService" class="service.ProductService"/>
</beans>
- 在TestSpring中进行测试
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.FoodMaker;
import pojo.Source;
import service.ProductService;
public class TestSpring {
public static void test(){
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"applicationContext.xml"}
);
// Source source = (Source) context.getBean("source");
//
// System.out.println(source.getFruit());
// System.out.println(source.getTaste());
// System.out.println(source.getSize());
//
// FoodMaker foodMaker = (FoodMaker)context.getBean("foodMaker");
// System.out.println(foodMaker.makeFood());
ProductService service = (ProductService)context.getBean("productService");
service.doSomeService();
}
public static void main(String[] args) {
test();
}
}
-
在Package【aspect】下准备日志切面【LoggerAspect类】
在此之前要先添加aspectJweaver依赖
package aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
}
- 在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" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean name="source" class="pojo.Source">
<property name="fruit" value="西瓜"/>
<property name="taste" value="草莓味"/>
<property name="size" value="大份"/>
</bean>
<bean name="foodMaker" class="pojo.FoodMaker">
<property name="source" ref="source"/>
</bean>
<bean name="productService" class="service.ProductService"/>
<bean id="loggerAspect" class="aspect.LoggerAspect"/>
<!-- 配置AOP -->
<aop:config>
<!-- where:在什么地方做添加 -->
<aop:pointcut id="loggerCutPoint" expression="execution(* service.ProductService.*(..))"/>
<!-- what:做什么增强, -->
<aop:aspect id="logAspect" ref="loggerAspect">
<!-- when:在什么时机 -->
<aop:around pointcut-ref="loggerCutPoint" method="log"/>
</aop:aspect>
</aop:config>
</beans>
-
再次运行TestSpring,我们可以发现代码并没有变,但是在业务方法的前后都输出了日志信息。
参考自cnblogs-@我没有三颗心脏