Spring
- 目前主流的Java Web开发框架,是Java世界最成功的框架。
- Spring由Rod johnson创立,有interface21为基础进行开发最终,于2004年3月24日发布正式版1.0
- Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架及非入侵式框架。
- 支持事务处理,对框架进行整合的支持!
组成
IoC (控制反转)
指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们使用 new 创建,而使用 Spring 之后,对象的创建都交给了 Spring 框架。
IOC推导
先写UserDao层接口
package com.juran.dao;
public interface UserDao {
String getUser();
}
再写UserDao接口实现类
package com.juran.dao;
public class UserDaoImpl implements UserDao{
@Override
public String getUser() {
return "普通调用成功";
}
}
然后再写UserService实现类
package com.juran.service;
public interface UserService {
String getUser();
}
最后再写UserService实现类
package com.juran.service;
import com.juran.dao.UserDao;
import com.juran.dao.UserDaoImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Override
public String getUser() {
userDao = new UserDaoImpl();
return userDao.getUser();
}
}
进行测试
import com.juran.service.UserServiceImpl;
import com.juran.service.UserService;
public class Test {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
String result = userService.getUser();
System.out.println(result);
}
}
按照我们原来认知里的操作编写代码,这样是没有问题的
UserDao实现类增加一个
package com.juran.dao;
public class UserDaoImpl2 implements UserDao{
@Override
public String getUser() {
return "实现类2";
}
}
之后我们再去service实现类里修改对应的实现
package com.juran.service;
import com.juran.dao.UserDao;
import com.juran.dao.UserDaoImpl;
import com.juran.dao.UserDaoImpl2;
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Override
public String getUser() {
userDao = new UserDaoImpl2();
return userDao.getUser();
}
}
那如果我们再写一个UserDao接口的实现类呢?我们是不是又按照相同的方法去修改service层,假设需求量大这种方法就完全不适用了。每次改动都需要修改大量的service实现类,这种方法耦合性太高,独立性就比较差。我们所需要的是高内聚度和低耦合。
解决耦合性较高问题
我们可以在service实现类中留一个setter接口,进而可以实现动态选择Dao层的实现类
package com.juran.service;
import com.juran.dao.UserDao;
public class UserServiceImpl implements UserService{
private UserDao userDao;
//使用set接口进行动态实现类选择。
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public String getUser() {
return userDao.getUser();
}
}
测试
import com.juran.dao.UserDaoImpl;
import com.juran.dao.UserDaoImpl2;
import com.juran.service.UserServiceImpl;
public class Test {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoImpl());
String result1 = userService.getUser();
System.out.println(result1);
//再次使用setter去选择实现类
userService.setUserDao(new UserDaoImpl2());
String result = userService.getUser();
System.out.println(result);
}
}
这种思想,从本质上解决了问题,我们的程序员不再去管理对象的创建了,更多的去关注业务的实现,耦合性大大降低,这也就是IOC的原形型。
IOC本质
控制反转是一种设计思想,DI(依赖注入)是实现IOC的一种方法。没有IOC的程序中,我们使用面向对象编程,对象的创建与对象之间的依赖关系完全硬编码再程序中,对象创建由程序自己控制,控制反转后将对象的创建交给第三方,控制反转:获得依赖对象的方式反转了。
通常,每个单独的 XML 配置文件都代表您架构中的一个逻辑层或模块,您可以使用应用程序上下文构造函数从所有这些 XML 片段加载 bean 定义。
控制反转时通过一种描述(xml或者注解),通过第三方去生产或获取特定对象的方式,再spring中实现控制反转的是Ioc容器,其实现方法为依赖注入。
控制反转(IOC)大致可以理解为程序由主动执行,变成被动接收
AOP(面向切面编程)
用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
AOP核心业务功能 及 周边功能
- 核心业务功能::登录、增加数据、删除数据
- 周边功能:性能、日志及食物管理登录
周边思想即为spring中的Aop切面思想。
在AOP思想中,核心业务功能及切面功能是独立开发的,然后将核心功能与切面功能编织在一起,这就是AOP思想。
AOP 目的
AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来 ,便于减少系统的重复代码 ,降低模块间的耦合度 ,并有利于未来的可拓展性和可维护性 。
AOP 当中的概念:
- 切入点(Pointcut)
在哪些类,哪些方法上切入(where ) - 通知(Advice)
在方法执行的什么实际(when: 方法前/方法后/方法前后)做什么(what: 增强的功能) - 切面(Aspect)
切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强! - 织入(Weaving)
把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
AOP 编程
- 在service包中创建类【ProductService】类
package com.juran.service;
public class ProductService {
public void doSomeService(){
System.out.println("doSomeService");
}
}
- XML文件中装配该Bean:
<bean name="productService" class="com.juran.service.ProductService"/>
- 编写测试类,运行测试。
- 在 Packge【aspect】下准备日志切面 【LoggerAspect】类:
package com.juran.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean name="productService" class="com.juran.service.ProductService"/>
<bean id="loggerAspect" class="com.juran.aspect.LoggerAspect"/>
<!-- 配置AOP -->
<aop:config>
<!-- where:在哪些地方(包.类.方法)做增加 -->
<aop:pointcut id="loggerCutpoint" expression="execution(* com.juran.service.ProductService.*(..)) "/>
<!-- what:做什么增强 -->
<aop:aspect id="logAspect" ref="loggerAspect">
<!-- when:在什么时机(方法前/后/前后) -->
<aop:around pointcut-ref="loggerCutpoint" method="log"/>
</aop:aspect>
</aop:config>
</beans>
- 再次运行 TestSpring 中的测试代码,代码并没有改变,但是在业务方法运行之前和运行之后,都分别输出了日志信息: