整合性框架,设计性框架
非侵入式:依赖注入是IOC的最经典表现
AOP:面向切面编程
OOP面向切面编程
Spring是一个容器因为它包含并管理应用对象的生命周期
springbeans包也就是Ioc实现的包
<?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>:定义spring所管理的一个对象
id:该对象的唯一标示,注意:不能重复,在通过类型获取bean的过程中可以不设置
class:此对象所属类的全限定名
-->
<bean>
</bean>
</beans>
每一个bean相当于spring管理的一个对象
spring 配置支持单例
scope="singleton"
IOC 和AOP
IOC
IOC 是什么?
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
用图例说明一下,传统程序设计如图2-1,都是主动去创建相关对象然后再组合起来:
图2-1 传统应用程序示意图
当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了,如图2-2所示:
图2-2有IoC/DI容器后程序结构示意图
IOC 能做什么?
IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。
IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
IOC 和DI:
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
●谁依赖于谁:当然是应用程序依赖于IoC容器;
●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
如何获取spring beans 管理的bean
//Person bean = (Person) applicationContext.getBean("person");
//Person bean = (Person) applicationContext.getBean(Person.class);
Person bean = applicationContext.getBean("person",Person.class);
IOC底层实质上就是一个对象工厂
1.IOC容器读取Bean实例以前,需要先将IOC容器本身实例化。
2.spring提供了IOC容器的两种实现方式,
2.1BeanFactoryIOC容器的基本试下是Spring内部的基础,是面向spring本身的
2.ApplicationContext BeanFactory的子接口,提供了高级的实现,几乎所有场合都何使用ApplicationContext而不是底层的BeanFactory
Application的基本实现类
IOC把程序员的管理权反转给程序本身(反射)
DI 把具有依赖关系的属性进行赋值
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //相对路径,
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("");//绝对路径
xml的namespace作用:
作用就是规定我们只能在命名空间使用那些标签
p标签命名空间
<bean id ="student4" class="com.spring.demo.di.Student" p:age="11" p:name="liwenjie" p:sex="男" p:score="90">
value可以引用一些字面量数据没办法引用对象这个时候就需要ref 去当前容器管理下去找对于的id
ref 的两种实现方式
property
p:id命名-ref
<bean id ="student4" class="com.spring.demo.di.Student" p:age="11" p:name="liwen" p:sex="男" p:score="90" p:teacher-ref="teacter">
</bean>
<bean id="student" class="com.spring.demo.di.Student" >
<property name="age" value="11"></property>
<property name="name" value="frist"></property>
<property name="sex" value="frist"></property>
<property name="teacher" ref="teacter"></property>
</bean>
级联属性:
<bean id="student" class="com.spring.demo.di.Student" >
<property name="age" value="11"></property>
<property name="name" value="frist"></property>
<property name="sex" value="frist"></property>
<property name="teacher" ref="teacter"></property>
<property name="teacher.tName" value="级联" ></property>
</bean>
定义在内部的bean只能在定义bean的内部访问
<bean id="student6" class="com.spring.demo.di.Student" >
<property name="age" value="11"></property>
<property name="name" value="frist"></property>
<property name="sex" value="frist"></property>
<property name="teacher">
<bean class="com.spring.demo.di.Teacher" id ="tt">
<property name="tName" value="内部类"> </property>
<property name="age" value="12"> </property>
</bean>
</property>
</bean>
list map set 在xml中的表示
也可以使用util:list为其赋值
<bean id="teacter2" class="com.spring.demo.di.Teacher">
<property name="tName" value="集合"></property>
<property name="age" value="12"></property>
<property name="students">
<list>
<ref bean="student"/>
<ref bean="student2"/>
<bean name="stu" class="com.spring.demo.di.Student">
<property name="age" value="1"></property>
</bean>
</list>
</property>
<property name="map">
<map>
<entry>
<key>
<value>11</value>
</key>
<value>map测试</value>
</entry>
</map>
</property>
<property name="strings" ref="strings"></property>
<property name="set" >
<value>set测试</value>
</property>
</bean>
<util:list id="strings">
<value>util测试</value>
<value>util测试2</value>
</util:list>
工厂模式:就是隐藏对象的创建模式,我们获取类只需要通过工厂就可以,类创建的过程由工厂为我们实现。
spring分为两种bean 一种是不同bean 还有一种就是我们下面说到的FactoryBean
FactoryBean:
1.配置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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util" xmlns:ref="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<bean id="myfatcory" class="com.spring.demo.FactoryBean.MyFactory"></bean>
</beans>
2.类
package com.spring.demo.FactoryBean;
/**
* Created by lwj32 on 2020/6/4.
*/
public class Car {
private String carName;
private Double price;
public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"carName='" + carName + '\'' +
", price=" + price +
'}';
}
}
3.工厂实现spring的FactoryBean
package com.spring.demo.FactoryBean;
import org.springframework.beans.factory.FactoryBean;
/**
* Created by lwj32 on 2020/6/4.
*/
public class MyFactory implements FactoryBean<Car> {
@Override
public Car getObject() throws Exception {
Car car =new Car();
car.setCarName("宝马");
car.setPrice(200000.0);
return car;
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
Spring中Bean的作用域scope
https://www.cnblogs.com/mfrank/p/10498056.html因为在最新版本(5.2.0.BUILD-SNAPSHOT)中request session
早就被移除了
作用域设置为
prototype时两个的地址值时不相同的singleton是相同的
如果spring管理的容器有单例的话会在容器初始化的时候就创建对象,prototype因为每次使用就用到所以不一样
springbean生命周期:
1.调用构造方法创建对象
2.注入值
3.初始化
4.使用
5.销毁
bean的后置处理器(对所有bean进行操作)
package com.spring.demo.BeanLife;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* Created by lwj32 on 2020/6/10.
*/
public class AfterHanlder implements BeanPostProcessor {
//初始化以前的操作
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
PeoPle peoPle = (PeoPle) bean;
if(peoPle.getName().equals("zhangshan")){
peoPle.setAge(1222);
}else {
return peoPle;
}
return peoPle;
}
//初始化以后的操作
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
引入静态文件:
通过springframework
<!-- <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="db.properties"></property>
</bean>
-->
<context:property-placeholder file-encoding="utf-8" location="db.properties" ></context:property-placeholder>
自动装配:
自动装配的属性给字面量的属性也就是ref 和嵌套bean
也可以通过
autowire="byName"
byName :通过spring管理的bean id 去匹配
byType 通过spring管理bean的类型去匹配
使用注解标识组件
@Component
@Repository
@Service
@Controller
添加注解的同时也要在xml中配置相关的扫描
<context:component-scan base-package="com.adguider">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
对设置注解的类进行进行扫描并创建bean,这些注释的类的bean的id是这些类的首字母小写作为id
组件扫描的包含和删除
这个时候我想过这么一个问题,为啥spring+springmvc中要 这样配置一个只扫描controller 一个不扫描controller这里面包含一个父子容器的关系
首先配置的是Spring容器的初始化加载的application文件,然后是SpringMVC的前端控制器(DispatchServlet),当配置完DispatchServlet后会在Spring容器中创建一个新的容器。其实这是两个容器,Spring作为父容器,SpringMVC作为子容器。
https://www.cnblogs.com/liu-eagles/p/7846944.html这个解释的非常明了。
//springmvc配置
<context:component-scan base-package="com.xxx" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
//spring配置
<context:component-scan base-package="com.xxx">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
大体理解就是
首先spring 和springmvc相当于两个容器而spring是父容器,springmvc为子容器,子容器可以访问夫容器中的bean,首先我我们在访问Controller时其中通过@Autowite可以访问父容器中的service其实这个道理和前面讲到的在bean标签中加入autowite是一个道理。
那么我们可以spring都去扫描吗回答是否定的,因为spring会加载controller 所以springmvc没有controller对象,无法提供服务
AOP解释
含义就是将我们要做的事情交给代理对象去做,最重要的是要保证最后结果一致。
代理模式实现
代理模式的三个对象:1.代理对象,2目标对象3.原始对象