三大框架:业务层框架Spring+IoC+DI
往期文章:jsp与cookie、重定向与RESTFul架构支持
下一章节: 持久层框架MyBatis
初识Spring框架
MyBatis 入门/mybatis/mybatis-dyr53b5w.html
1.解决什么问题
业务层:主要处理业务逻辑
,需要对象,以前是自己new对象,管理对象,可以吧对象放在list或map中。
2.是什么?
是业务层框架,主要有两个功能
2.1 是ioc容器,ioc容器他提供了一个hashMap(提供了一个容器来存放对象)
IOC: Inversion of Control(控制反转)
控制反转:将对象的创建权反转给(交给)Spring
DI:依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
●谁依赖于谁:当然是应用程序依赖于IoC容器;
●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
DI和IOC的关系: DI不能单独存在,DI需要在IOC的基础上来完成.
这样做得好处:做到了单一职责,并且提高了复用性,解耦了之后,任你如何实现,使用接口的引用调用的方法,永远不需要改变
2.2 aop功能,动态代理(静态代理详解/whirly/p/10154887.html)由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。
3.如何使用?
3.1 通过xml配置方式使用(更加麻烦)
3.2 创建springboot项目,内置了spring(代码量少,新手入门建议学spring这种方法)
注册时在业务层判断用户名是否存在。
获取商品价格时,判断用户是否是会员,商品有没有参加店铺活动,有没有参加商城活动。
Spring的野心
springMVC作为WEB框架深受企业爱戴,它会自己管理Controller,来创建其实例。Mybatis作为持久层优秀的框架,它也自己管理持久对象。可以看到,各个诸侯都自己管理对象,而要想让它们对象复用,那真是繁琐。
如何破局呢?要想发号施令其它人听,最好的解决办法就是扼住他们的咽喉。在java的世界里最重要的无疑就是对象的生命周期管理。于是spring以此为切入点,实现自己的统治。宣布所有对象由我来管理,springMVC你不再管理对象,由我来管理,你要用从我这拿。Mybatis你也不再管理对象,由我来管理,你要用从我这拿。你说管就管吗?这两个征战数年战功赫赫的大将军会听一个初出茅庐乳臭未干野小子的话?他们当然不会听,spring的话可以不听,但他们都要听开发者的。开发一个完整的系统有四个核心,WEB层支持、业务逻辑层、持久层支持、事务支持。而这就是它们的软肋,这就是它们的命门所在,它们只能完成一部分工作,不是一个整体解决方案。而spring并没有抹杀它们,而是依然高官厚禄,承认它们的市场地位,还赠与一个事务管理。一边打压一边拉拢,它们两位看看大势已去,只能俯首称臣。于是兵不血刃,一场变革悄然兴起,一个经典的三层框架诞生SSM (SpringMVC+Spring+Mybatis)。
故事很传奇,听的人很开心。可spring真就这么简单吗?如果这样想,你就大错特错了。例如:spring怎么来实现对象的管辖?怎么让不同技术之间能简单的互相配合?这才是spring的决胜之处。
为实现这些spring是煞费苦心,创新的形成了一套新的理论体系,可谓前无古人后无来者。其中最核心的是:IoC控制反转、DI依赖注入、SpringAOP面向切面编程、事务控制。
框架组成
Spring官网: http://spring.io
Spring是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。Spring框架的不光是技术牛,而是它的核心思想更牛,它不重复发明轮子,而是“拿来主义”,把业界做的最好的技术黏合起来形成一个强大的企业级的应用框架。
用springboot方式实现ioc
需求
1.拷贝webdemo倒工作区,直接把文件夹改名为spring01ioc,修改pom.xml中的antifactid和name,eclipse -->maven -->existing maven projects
导入eclipse
修改为pom.xml中的antifactid和name
2.在主包下面创建controller,创建UserController
@autowired spring框架会从ioc容器中取一个对象赋值给userService UserService userService
3.创建业务层Service
interface UserService{register}
@Service 与controller功能类似,由spring创建UserServicelmpl类对象
对象存放在spring框架中的ioc容器(hashMap)
class UserServicelmpl implements UserService
步骤1:创建接口
package com.tedu.webDemo.service;public interface UserService {public int register(String username);}
步骤2:创建一个接口的实现类
package com.tedu.webDemo.service;import org.springframework.stereotype.Service;//接口的实现类@Service //告诉spring框架为类创建一个对象//对象放在spring框架的ioc容器(hashMap)中public class UserServiceImp1 implements UserService{//返回类型最好用包装类型integer@Overridepublic int register(String username) {//控制层springmvc调用业务层//判断用户名是否存在//调用数据库层mybatisreturn 0;}}
创建控制层
步骤3:创建控制层
package com.tedu.webDemo.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.tedu.webDemo.service.UserService;import com.tedu.webDemo.service.UserServiceImp1;//创建控制层@RestControllerpublic class UserController {//以前//UserController依赖UserServiceImp1//UserController被UserServiceImp1控制UserServiceImp1 UserServiceImp1=new UserServiceImp1();//控制层调用业务层,对象是从ioc容器中取//对象的类型要写接口,不要写具体的实现类的类型//对象从spring框架中来//被框架控制//控制反转ioc inversion of controller@AutowiredUserService userService;@RequestMapping("/reg")//在控制层,业务层方法的第一行加断点//main() Debug AS//console 是否显示tomcat started on port 8080//localhost:8080/register F6,F8public String register(String username) {int state=userService.register(username);return "state="+state;}}
class UserServicelmpl2
以前创建对象把这个写死了 UserServicelmpl userServicelmpl = new UserServicelmpl()
创建对象时把对象改为接口 UserService userService = new UserServicelmpl2();
小结
这就是spring框架的IoC,控制反转。之前我们自己new出新类。new UserService(),现在由容器提供。
在java范畴中万物皆Object,在Spring中万物皆Bean。Bean是Spring的核心、基础、根源。
上面的方式很多同学会觉得不以为然,感觉还没有我们传统方式实现方便呢,new个对象不就可以了。凭空多个什么IoC,什么DI乱七八糟的感觉。是那样吗?不光大家这样觉得,业界开始时也对它嗤之以鼻,但随着Spring3.0的推出,随着注解方式的成为市场主流编程方式,它的力量开始展现,让我们这些俗人开始仰慕!这其中也包括我。
要不断的去适应ioc方式
生命周期:
查看步骤三 控制层
对象什么时候创建,什么时候被回收?
controller默认是系统启动时创建,系统关闭时回收
@scope(“singleton”)单例,只创建一个对象
@scope(" ")
http://localhost:8080/reg?username=a
debug跟踪流程
Singleton,prototype,session
scope:singleton单例,每次得到的对象是一样的
prototype: 每次得到的对象是个新的
分析
AccessCount应该只有一个
LogInfo是每次创建新的
UserCart是一个用户创建一个
需求
需求:网站上来一个用户加1,放在accessCount
用户购物车:userCart
日志:logInfo
实现
@component的功能与@service类似,加了@component后框架会创建对象,@service表示创建的是业务层对象,@component表示创建的是普通对象。
在com.tedu.webDemo.service包中创建三个类AccessCount、LogInfo、UserCart
AccessCount类
package com.tedu.webDemo.service;import org.springframework.context.annotation.Scope;import org.ponent;//组件:由框架管理的类@Component //@Component是组件//@controller,@restControler,@service都是组件//@controller,@restControler,是专门用来接收数据//@service类是专门处理数据的,是业务层的类@Scope("singleton")//单例,服务器启动时创建,关闭时 被回收public class AccessCount {}
LogInfo
package com.tedu.webDemo.service;import org.springframework.context.annotation.Scope;import org.ponent;//处理日志,记录每次访问的时间@Component@Scope("prototype")//每次通过@autowired拿对象,都会创建一个新的public class LogInfo {}
UserCart
package com.tedu.webDemo.service;import org.springframework.context.annotation.Scope;import org.ponent;//购物车 (浏览器打开的时候创建)@Component@Scope("session")//第一次访问时创建//关闭浏览器,对象被回收public class UserCart {}
修改:UserController 控制层
package com.tedu.webDemo.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Scope;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.tedu.webDemo.service.AccessCount;import com.tedu.webDemo.service.LogInfo;import com.tedu.webDemo.service.UserCart;import com.tedu.webDemo.service.UserService;import com.tedu.webDemo.service.UserServiceImp1;//创建控制层@RestController@Scope("prototype")public class UserController {//以前//UserController依赖UserServiceImp1//UserController被UserServiceImp1控制UserServiceImp1 UserServiceImp1=new UserServiceImp1();//控制层调用业务层,对象是从ioc容器中取//对象的类型要写接口,不要写具体的实现类的类型//对象从spring框架中来//被框架控制//控制反转ioc inversion of controller@AutowiredUserService userService;//从是spring框架的ioc容器中取对象@AutowiredAccessCount accessCount;@AutowiredLogInfo logInfo;@AutowiredUserCart userCart;//测试商品对象@RequestMapping("/test")public String test() {return accessCount.toString()+"<br>"+logInfo.toString()+"<br>"+userCart.toString();}@RequestMapping("/reg")//在控制层,业务层方法的第一行加断点//main() Debug AS//console 是否显示tomcat started on port 8080//localhost:8080/register F6,F8public String register(String username) {int state=userService.register(username);return "state="+state+this.toString();}}
http://localhost:8080/test
Debug AS执行
业务层有多个实现类
案例:生活中假如你女朋友是双胞胎,姐妹两长的一样,你会到家你发现,你女朋友 姐妹两人都在,这个时候你应该怎么去区分?
spring框架到ioc容器中找到所有的对象判断这个对象的类型,如果是UserService就赋值
@autowired
UserService userSerivce
interface UserService
class UserServicelmpl
@service
class UserServiceImpl2 implements UserService
自动装配类型
在service包中再创建一个UserServiceImpl2 类
package com.tedu.webDemo.service;import org.springframework.stereotype.Service;@Service//spring框架会自动为类创建对象//对象放在ioc容器中public class UserServiceImpl2 implements UserService {public int register(String username) {return 0;}}
创建两个业务层实现类,默认会出错
http://localhost:8080/reg
默认是根据类型找对象
根据类型找不到对象,再根据名字找对象
package com.tedu.webDemo.service;import org.springframework.context.annotation.Scope;import org.ponent;//处理日志,记录每次访问的时间@Component@Scope("prototype")//每次通过@autowired拿对象,都会创建一个新的//用完就回收public class LogInfo {}
```javapackage com.tedu.webDemo.service;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;//接口的实现类@Service //告诉spring框架为类创建一个对象//对象放在spring框架的ioc容器(hashMap)中//框架创建对象时,对象放在hashMap中,key是userServiceImplpublic class UserServiceImpl implements UserService{//返回类型最好用包装类型integer@Overridepublic int register(String username) {//控制层springmvc调用业务层//判断用户名是否存在//调用数据库层mybatisreturn 0;}}
package com.tedu.webDemo.service;import org.springframework.stereotype.Service;@Service//spring框架会自动为类创建对象//对象放在ioc容器中,key是userServiceImpl2public class UserServiceImpl2 implements UserService {@Overridepublic int register(String username) {return 0;}}
package com.tedu.webDemo.controller;import javax.websocket.Decoder.TextStream;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Scope;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.tedu.webDemo.service.AccessCount;import com.tedu.webDemo.service.LogInfo;import com.tedu.webDemo.service.UserCart;import com.tedu.webDemo.service.UserService;import com.tedu.webDemo.service.UserServiceImpl;//控制层@RestController@Scope("prototype")public class UserController {//以前//UserController依赖UserServiceImpl//UserController被UserServiceImpl控制//UserServiceImpl UserServiceImpl=new UserServiceImpl();//控制层调用业务层,对象是从ioc容器中取//对象的类型要写接口,不要写具体的实现类的类型//对象从spring框架中来//被spring框架控制,依赖框架//控制反转 ioc inversion of controller@Autowired//默认是根据类型赋值//如果框架有2个对象的类型是UserService,赋值失败//先根据类型赋值,失败后,再根据对象的名称赋值//userServiceImpl,对象//userServiceImpl2,对象UserService userServiceImpl;@AutowiredUserService userServiceImpl2;@Autowired@Qualifier("userServiceImpl2")//框架hashmap.get(userServiceImpl2),能取到对象//对象赋值给userService//先根据类型找到2个对象,赋值失败UserService userService;@RequestMapping("/test2")public String test2() {return userServiceImpl.toString()+"<br>"+userServiceImpl2.toString()+"<br>"+userService.toString();}//从spring框架的ioc容器中取对象@AutowiredAccessCount accessCount;@AutowiredLogInfo logInfo;@AutowiredUserCart userCart;@RequestMapping("/test")public String test() {return accessCount.toString()+"<br>"+logInfo.toString()+"<br>"+userCart.toString();}@RequestMapping("/reg")//在控制层,业务层方法的第一行加断点//main() debug as //console 是否显示 tomcat started on port 8080//localhost:8080/register F6,F8public String register(String username) {int state=userServiceImpl.register(username);return "state="+state+this.toString();}}
package com.tedu.webDemo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class WebDemoApplication {public static void main(String[] args) {SpringApplication.run(WebDemoApplication.class, args);}}
Run as执行: