spring特性
spring优点
1.是一个免费的开源框架(容器)
2.轻量级的非入侵式的框架
3.控制反转(IOC),面向切面编程(AOP)
4.支持事务的处理,对框架整合的支持
spring的组成
七大模块
拓展
springboot
一个快速开发的脚手架
基于springboot可以快速开发单个微服务
约定大于配置!
springcloud
基于springboot实现的
缺点
违背了原来的理念,配置十分繁琐,人称“配置地狱”
IOC(重点重点)
IOC理论推导
1.UserDao接口
2.UserDaoImpl实现类
3.UserService业务接口
4.UserServiceImpl业务实现类
在之前的业务中,用户的需求可能会影响原来的代码,我们需要根据用户的需求去修改代码,如果程序代码量十分大,修改一次的成不代价十分昂贵
我们使用一个set接口实现
下面展示一些 内联代码片
。
private UserDao userDao;
//利用set动态实现值的注入
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
之前,程序是主动创建对象,控制权在程序员手上
** 使用set注入后,程序不再具有主动性,而是被动的接受对象**
public static void main(String[] args) {
//用户实际调用的是业务层,dao层他们不需要接触
UserService userService = new UserServiceImpl();
((UserServiceImpl)userService).setUserDao(new UserSqlserverImpl());
userService.getUser();
}
仔细看这段代码,有多个impl的时候,需要调用哪个impl,只需要在set传入对应的参数就好,而不需要我们再手动创建了
这种思想从本质上解决了问题,我们的程序员不用再去管理对象的创建了。系统的耦合性大大降低,可以更加专注地在业务的实现。这是IOC的原型!
IOC使用
这个就是xml文件的配置,
bean里面的class是指定实体类
property标签就是指定类的属性,value就是赋值,配合下一张图看
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="com.kuang.pojo.hello">
<!-- collaborators and configuration for this bean go here -->
<property name="str" value="Spring"/>
</bean>
</beans>
public class hello {
private String str;
public String getStr(){
return str;
}
public void setStr(String str){
this.str = str;
}
@Override
public String toString() {
return "hello{" +
"str='" + str + '\'' +
'}';
}
}
那要怎么用呢
容器已经帮我们创建好了
getBean即可调用
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
hello hello = (com.kuang.pojo.hello) context.getBean("hello");
hello.toString();
System.out.println(hello.toString());
}
- 通过类型 获取IOC容器中bean的实例
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
com.kuang.pojo.hello bean = context.getBean(com.kuang.pojo.hello.class);
- PS:如果有多个该类型组件则会报错
- 解决,getBean前一个参数可以加上id名,这样就会只返回单个且不用强转
com.kuang.pojo.hello bean = context.getBean("hello",com.kuang.pojo.hello.class);
** 复杂赋值 **!!!!!
book类里面有别的类,应该怎么赋值呢
这里引进ref这个标签,ref就是引用外面的一个值,相当于引用外部bean
那如果不用ref呢,可以这样套娃,相当于引用内部bean(但是内部bean不能被获取到,只能内部使用)-----直接在beans里面写的bean为外部的,但是bean里的内嵌bean则是外部的
<bean id="book" class="com.kuang.pojo.book">
<!-- collaborators and configuration for this bean go here -->
<property name="Car">
<bean>
</bean>
</property>
</bean>
- 那么如何为list,map赋值呢,property里面可以添加< list >标签,map也如下
级联属性:属性的属性就叫级联属性
细节
一、
1.ApplicationContext(容器的接口)
new ClassPathXmlApplicationContext(“beans.xml”);IOC容器在类路径下;
FileSystemXmlApplicationContext(“F://beans.xml”);IOC容器在磁盘路径下;
二、
1)组件的创建工作是由容器完成的
2)容器中对象的创建是在容器创建完成前就已经创建好了(不是get的时候才创建)
3)1个bean对应一个对象,同一个组件(bean)在容器中是单实例的
4)容器中如果没有该组件,获取组件会报错
容器中没有hello123456这个组件,则会报错
Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘hello123456’ available
5)IOC容器在创建这个组件对象的时候,(property)会利用setter方法为javaBean的属性进行赋值
6)javaBean的属性名是由set方法中的实现的(所以所有的get,set方法都应该自动生成)
bean的作用域
- prototype:多实例
1)容器启动默认不会去创建多实例bean
2)在获取的时候(类似getbean())创建bean
3)每次获取都会创建一个新的对象 - singleton:单实例(默认的)
1)在容器启动完成之前就已经创建好对象保存在容器中
2)任何时候获取都是获取之前创建好的那个对象
request:在web环境,同一次请求创建一个一个bean实例(没用)
session:在web环境下,同一次会话创建一个bean实例(没用)
工厂模式
自己实现普通工厂
工厂模式:创建对象,有一个类帮你去创建对象,这个类就叫工厂
AirplaneFatory.getAirPlane(String jzName);
静态工厂:工厂本身不用创建对象,都是通过静态方法调用,工厂类.工厂方法名();
实例工厂:工厂本身需要调用对象:
工厂对象.工厂方法名();
<!--这样麻烦-->
<bean id="airplane01" class="com.kuang.pojo.AirPlane">
<property name="jzName" value="张三"></property>
</bean>
静态工厂(不需要创建工厂本身)
factory-method="getAirPlane"指定哪个方法是工厂方法
constructor-arg value可以为静态工厂传参
<bean id="airplane02" class="com.kuang.fatory.AirPlaneStaticFactory" factory-method="getAirPlane">
<constructor-arg value="李四"></constructor-arg>
</bean>
实例工厂
1.先配置工厂实例
2.用factory-bean配置我们要创建的对象用哪个工厂创建
3.用factory-method指定使用哪个工厂方法
<bean id="airPlaneInstanceFactory" class="com.kuang.fatory.AirPlaneInstanceFactory"></bean>
<!--factory-bean:指定当前对象创建使用哪个工厂-->
<bean id="airplane03" class="com.kuang.pojo.AirPlane"
factory-bean="airPlaneInstanceFactory" factory-method="getAirPlane">
<constructor-arg value="王五"/>
</bean>
FactoryBean
- FactoryBean是Spring指定的一个工厂,只要实现了这个接口的实现类,Spring都认为是一个工厂
- Spring会自动调用工厂方法创建实例
- 工厂类的编写
/**
* 1.编写一FactoryBean的实现类
* 2.在spring配置文件中进行注册
*/
public class MyFactoryBeanImple implements FactoryBean<AirPlane> {
/**
* getObject:工厂方法
* @return 返回创建的对象
* @throws Exception
*/
@Override
public AirPlane getObject() throws Exception {
AirPlane airPlane = new AirPlane();
airPlane.setYc("1");
return airPlane;
}
/**
* 返回创建对象的类型
* @return Spring会自动调用这个方法来确认创建的对象是什么类型
*/
@Override
public Class<?> getObjectType() {
return AirPlane.class;
}
/**
* 确认是不是单例
* false:不是
* true:是
* @return
*/
@Override
public boolean isSingleton() {
return false;
}
}
- 注意:FactoryBean无论是单多实例,都是在获取时才创建对象
bean的生命周期
- IOC容器中注册的bean
1)单例bean,容器启动的时候就会创建好,容器关闭也会销毁创建的bean
2)多实例bean,获取的时候才创建
bean标签里的
destroy-method,init-method(方法不能带有参数)
单实例容器关闭时销毁bean
多实例容器关闭互换调用销毁方法
引用外部属性文件
数据库连接池作为单实例是最好的。(略,以后直接springboot集成)
通过注解创建controller,service,dao
某个类上添加任何一个注解都能快速将这个组件加入到IOC容器的管理中
@Controller:控制器;(推荐给控制器层(servlet包下的这些))的组件添加这个注解
@Service:业务逻辑;推荐业务逻辑层添加这个注解;Service
@Repository:给数据库层(持久化层:dao层)的组件添加这个注解
@Component,给不属于以上几层的组件添加这个注解
注解可以随便加:spring底层不会去验证你的组件师傅如你注解所说。(但是为了编码规范)
- 使用注解将组件快速加入到容器中需要几步:
1)给要添加的组件上标四个注解中的任何一个
2)告诉spring自动扫描这个注解(自动扫描)
3)获取所用的组件的id就是是类名的首字母小写
4)一定要导入Aop包,因为他是支持注解模式
5)使用注解加入到容器中的组件,和使用配置加入到容器中的组件行为都是默认一样的
6)组件的作用域默认就是单例的删除线格式
context:component-scan:自动组件扫描
base-package="":指定扫描的基础包,会把基础包及下面的所有加了注解的类早点扫描加入IOC容器
<context:component-scan base-package=""></context:component-scan>
- 有选择的扫描类下的包
<context:include-filter type="" expression=""/>扫描只要哪些
<context:exclude-filter type="" expression=""/>扫描不要哪些
type=“annotation”:指定排除规则:按照注解进行排除。标注指定注解的组件不要
type=“assignable”:指定排除某个具体的类
expression="":写注解的全类名
<context:component-scan base-package="">
<context:include-filter type="annotation" expression=""/>
<context:exclude-filter type="" expression=""/>
</context:component-scan>
各种注解的使用
@Respository
- 组件名的改写
@Respository("xxx")
@Scope
- 多实例的修改
@Scope(value=“prototype”)
@Respository("xxx")
@Scope(value="prototype")
public class BookDao{
}
标签方法:
context:index-filter</context:index-filter>
<context:component-scan base-package="">
<context:include-filter type="" expression=""/>
<context:exclude-filter type="" expression=""/>
</context:component-scan>
DI依赖注入
- @Autowired
自动装配:自动为这个属性赋值(可以不用new了)
@Controller
public class BookServlet{
@Autowired
private BookService bookService;
}
@Qualifier
1)按照类型去容器中找到对应的组件bookService = ioc.getBean(BookService);
2)没找到就抛异常
3)找到多个?
1)按照变量名作为id继续匹配:BookService,BookServiceExt
2)没有匹配上?报错,原因是因为按照变量名作为id继续匹配的
@Qualifier:指定一个名作为id,让spring别用变量名作为id匹配(写在Autowired下面即可)
找到:装配
找不到:报错
所以我们发现Autowired是一定要装备上的。
但是可以这样
@Autowired(required=false)
找不到自动装配null
方法上有Autowired注解
@Resource,@Inject
@Autowired:Spring自己的注释
@Resource:java的标准
也能装配
@Resource因为他是标准的所以扩展性更强