java-spring
Spring-IOC
ioc概念
控制反转
把对象创建和对象之间的调用过程,交给Spring 进行管理。
目的就是,为了降低耦合度,因为当你想在一个类当中调用另外一个类的方法,你需要获得另外一个类的实例
IOC的底层原理:
包括xml解析,工厂模式,反射

引入工厂模式之后:

IOC解耦过程

IOC接口:
1Ioc思想基于IOC容器完成,IO容器底层就是对象工厂 2Spring提供IOC容器实习两种方式:两个接口 1)BeanFactory :IOC容器基本实现,Spring内部的使用接口,不提供给开发人员进行使用 2)ApplicationContext :BeanFactory接口的子接口,提供更强大的功能,一般开发人员使用 区别: BeanFactory 加载配置文件的时候不会创建对象,在获取对象的时候才创建。 ApplicationContext ,加载文件的时候,会将配置文件里面的对象进行创建。
获取IOC容器的方式
通过beanFactory

通过applicationContext获取

3 ApplicationContext接口实现类

FileSystemXmlApplicationContext从盘符路径开始查找配置文件,绝对路径
ClassPathXmlApplicationContext项目路径下查找-----一般使用
IOC操作Bean管理
Bean管理是什么:
1Spring创建对象
2Spring注入属性
Bean管理操作两种方式
基于xml配置文件方式实现
基于注解方式实现
JOC操作Bean管理--基于xml方式
基于xml方式创建对象
</bean> <bean id="usert" class="com.quan.Usert" > </bean>
1)在sprin配置文件中,使用bean标签,标签理添加相应的属性,就可以实现对象创建
2)bean标签的属性
id:属性 =唯一标识
class属性=类的全路径
3)默认使用无参构造方法完成对象的创建
bean标签的属性init-method= destroy-method=
先说两个接口先:
InitializingBean DisposableBean 标记接口 ,
主要实现Spring 执行bean时的初始化和销毁时某些方法
实现InitializingBean ,需要实现afterPropertiesSet,就是设置所有的属性之后做什么
实现DisposableBean 实现destory(),就是Spring 容器释放该bean之后做些什么
public class InitialDisp implements InitializingBean, DisposableBean {
public void destroy() throws Exception {
System.out.println("destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("afterProper");
}
}
执行:
public class BETest {
public static void main(String[] args) {
/*
ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable
ApplicationContext:应用上下文
Lifecycle:负责context的生命周期进行管理,提供start(),stop() 以及isRunning()
Closeable:用于关闭组件,释放资源
ConfigurableApplicationContext 接口的作用就是设置上下文 ID,设置父应用上下文,添加监听器,刷新容器,关闭,判断是否活跃等方法
*/
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
InitialDisp id = (InitialDisp)ac.getBean("initdesp");
System.out.println(id);
ac.close();
}
}
/*
re:
afterProper
com.quan.hll.InitialDisp@1f36e637
destroy
*/
但是不建议使用这两个接口
可以指定类中的某个方法为两个阶段的方法:init-method= destroy-method=
上面的类不在继承那两个接口
再bean配置文件当中:
<bean id="initdesp" class="com.quan.hll.InitialDisp" init-method="afterPropertiesSet" destroy-method="destroy"></bean>
设置bean加载和销毁所调用的方法
</bean> <bean id="usert" class="com.quan.Usert" init-method="init" destroy-method="destroy"> </bean>
test;
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
Usert usert = (Usert)ac.getBean("usert");
usert.say();
//关闭ioc容器
((ClassPathXmlApplicationContext) ac).close();

基于xml方式注入属性
1)DI: 依赖注入,就是注入属性,是IOC的一种实现方式
依赖注入-setter方法;
11类需要各个属性的set方法
22配置文件中先创建对象,再注入属性

依赖注入---构造方法
1)需要创建有参构造函数
2)配置文件中使用constructor-arg标签
第一个类:
View Code第二个类:
View Codespring-config.xml配置
<!-- 创建User对象,id是这个资源的唯一表示-->
<bean id="user" scope="prototype" class="com.quan.User">
<!-- 通过构造方法注入-->
<constructor-arg index="0" value="QQgou"/>
<constructor-arg index="1" ref="usert"/>
<!-- 这里的user实例里面的name属性会被下面的设置替代,如果没有就是构造器的值-->
<property name="name">
<value>QQSpring</value>
</property>
<!-- name这里是指User类里面的属性usert 这里的ref是指下面的bean-->
<property name="usert" ref="usert">
</property>
</bean>
<bean id="usert" class="com.quan.Usert" init-method="init" destroy-method="destroy">
</bean>
re;
init see you
how to sayQQSpring
see you
注:加颜色就是通过构造方法注入的形式,里面还有属性是其他类的设置

IOC操作Bean管理-xml注入其他类型属性
字面量
null值
再熟悉值里面不要设置value属性,直接加入null标签
<bean id="user" class="com.quan.hlll.User"> <property name="name"> <null></null> </property> </bean>
特殊符号<<>>
进行转义操作
<bean id="user" class="com.quan.hlll.User"> <property name="name" value="<><<南京>>"></property> </bean>

把带特殊符号内容写到CDATA
<property name="name"> <value><![CDATA[<<南京>>]]></value> </property>
注入属性-外部bean
person累有一个属性为hello对象类型
<bean id="person" class="com.quan.hll.javaConfig.Person.Person">
<constructor-arg index="0" value="QQQ"/>
<constructor-arg index="1" ref="hello" />
</bean>
<bean id="hello" class="com.quan.hll.javaConfig.Hello.Hello"></bean>

注意属性-内部bean和级联赋值
View Code
通过构造函数(其实set方法也是可以的)
<bean id="person" class="com.quan.hll.javaConfig.Person.Person">
<constructor-arg index="0" value="QQQ"/>
<constructor-arg index="1" >
<bean class="com.quan.hll.javaConfig.Hello.Hello"></bean>
</constructor-arg>
</bean>
内部定义的累有属性的时候
注意:建议在类的内部进行内部类的定义:
<bean id="person" class="com.quan.hll.javaConfig.Person.Person">
<constructor-arg index="0" value="QQQ"/>
<constructor-arg index="1" >
<bean class="com.quan.hll.javaConfig.Hello.Hello">
<property name="msg">
<value>ourmsg</value>
</property>
</bean>
</constructor-arg>
</bean>

bean属性值的注入两种xml格式
类
View Code
<!-- 使用属性标签property其的下级value属性进行值的注入,-->
<bean id="mconstructor" class="com.quan.hll.manyConstruntor.MConstructor" >
<property name="name" >
<value>quan</value>
</property>
<property name="addr">
<value>gd</value>
</property>
<property name="age">
<value>23</value>
</property>
</bean>
<!-- 使用快捷方式进行值的注入,-->
<bean id="mconstructor" class="com.quan.hll.manyConstruntor.MConstructor" >
<property name="age" value="23"/>
<property name="addr" value="gd"/>
<property name="name" value="q1234"/>
</bean>
IOC操作Bean管理(xml-注入集合属性)
格式:
<list value-type="java.lang.String"> <value>list里面的元素</value> ... </list> <set> <value>set元素</value> ... </set> <map> <entry key=key值 value=key值对应的value/> .... </map> <props> <prop key=key值>value值写这里</prop> ..... </props>
eg
<bean id="springlist" class="com.quan.hll.List.SpringList"> <!-- list--> <property name="lists" > <list value-type="java.lang.String"> <value>quan</value> <value>quan</value> <value>quan2</value> </list> </property> <!-- set--> <property name="sets"> <set> <!-- 因为set属性不允许重复,只保留一个--> <value>quan</value> <value>quan</value> <value>quan2</value> </set> </property> <!-- Map--> <property name="maps"> <map> <!-- 同样只保留后者--> <entry key="one" value="QQQ"/> <entry key="one" value="ZZZ"/> <entry key="two" value="ZZZ"/> </map> </property> <!-- properties--> <property name="properties"> <props> <prop key="quan">shige213</prop> <prop key="zhi">shige321</prop> </props> </property> </bean>
类:
package com.quan.hll.List; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class SpringList { private List<Object> lists; private Set<Object> sets; private Map<Object,Object> maps; private Properties properties; public List<Object> getLists() { return lists; } public void setLists(List<Object> lists) { this.lists = lists; } public Set<Object> getSets() { return sets; } public void setSets(Set<Object> sets) { this.sets = sets; } public Map<Object, Object> getMaps() { return maps; } public void setMaps(Map<Object, Object> maps) { this.maps = maps; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } }
打印类:
[quan, quan, quan2] {one=ZZZ, two=ZZZ} {quan=shige213, zhi=shige321} [quan, quan2]


集合里面设置对象

把集合注入部分提取出来

<util:list id="publiclist" > <value>quan</value> <value>QQQ</value> </util:list> <bean class="com.quan.hll.List.SpringList" id="springList"> <property name="lists" ref="publiclist"/> </bean>
IOC操作Bean管理(FactoryBean)
Spring 有两类型bean,一种就是我们一直自己设置的普通bean,另一种就是工厂bean
普通bean ,再配置文件中定义bean类型究竟是返回类型
工厂bean,再配置文件地暖管一bean类型可以和而返回值不一样
工厂bean的理解与实现
1创建一个累,累作为工厂bean,实现接口FactoryBean
2实现接口里面的方法,再实现方法中定义返回的bean类型
public class Mybean implements FactoryBean { //返回bean类型 @Override public Object getObject() throws Exception { return null; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } }
这几个方法是可以自定义的,将Object类型改变为其他类型,救可以实现不同返回不同类型了

IOC操作Bean管理(bean的作用域)
bean的作用域:再Spring中,设置创建bean实例时单实例还是多实例
默认是单例
单例 - 每个Spring IoC 容器返回一个bean实例 singleton
原型- 当每次请求时返回一个新的bean实例 prototype
请求 - 返回每个HTTP请求的一个Bean实例
会话 - 返回每个HTTP会话的一个bean实例
全局会话- 返回全局HTTP会话的一个bean实例
再spring当中bean标签里面有属性scope,用于设置单实例还是多实例

ApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
for (int i = 0; i < 3; i++) {
User user = (User)ac.getBean("user");
System.out.println(user);
}
singleton作用域
共享一个实例bean,只创建一个实例,同一个地址
<bean id="user" class="com.quan.hlll.User" scope="singleton"/>
结果为:
/*socpe为sigleon的时候 com.quan.User@67784306 com.quan.User@67784306 com.quan.User@67784306 */
prototype作用域
每次注入这个类的时候,都创建一个实例
<bean id="user" class="com.quan.hlll.User" scope="prototype"/>
结果:
v/*socpe为prototype的时候 com.quan.User@63753b6d com.quan.User@6b09bb57 com.quan.User@6536e911 */
sigleton 和prototype的区别:
singleton时,加载spring配置文件时候就会创建单实例对象
prototype的时候,不是再加载spring配置文件时候创建对象,再调用getBean方法时候i创建多时了对象
IOC操作Bean管理(bean生命周期)
生命周期:从对象创建到对象销毁的过程
bean的生命周期
1通过构造器创建bean实例(无参构造)
22为bean的属性设置值和对其他bean的引用(调用set方法)
33调用bean的初始化的方法(需要进行配置初始化的方法)
44bean可以使用
55当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
public class User { public User(){ System.out.println("第一步"); } public String name; public void setName(String name) { this.name = name; System.out.println("第二部"); } public void initMethod(){ System.out.println("第三步"); } public void destroy(){ System.out.println("第五步"); } }
配置文件
<bean id="user" class="com.quan.hlll.User" init-method="initMethod" destroy-method="destroy"/>
public class Main { public static void main(String[] args) { //加载配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml"); User user = ac.getBean("user",User.class); System.out.println("第四步"); System.out.println(user); //手动让bean实例销毁,即关闭IOC容器 ((ClassPathXmlApplicationContext)ac).close(); } }

bean的后置处理器

一旦你实现了BeanPostProcessoer接口且将该处理器bean配置到配置文件中,那所有的bean都会
自动调用这个累实现的方法
有后置处理器之后的生命周期
(1)通过构造器创建bean实例(无参数构造) (2)为bean的属性设置值和对其他bean引用(调用set方法) (
3)把bean实例传递bean后置处理器的方法postProcessBeforeInitialization (4)调用bean的初始化的方法(需要进行配置初始化的方法) (5)把bean实例传递bean后置处理器的方法 postProcessAfterInitialization (6)bean可以使用了(对象获取到了) (7)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
IOC操作Bean管理(xml自动装配)少用
我们之前都是通过标签,标签属性,各种子标签去实现bean的创建,这种事手动装配
自动装配:
根据指定装配规则(属性名称或者属性类型),Spring自动将配置的属性值进行注入
主要使用 bean里面的autwire属性进行实现

使用byType,如果IOC容器当中存在多个同类型的Bean就会出现错误
IOC操作Bean管理(引入外部属性文件)
应用场景
我们将一些固定的值写道变量配置文件当中
以后如果需要该的时候,我们不需要去动配置文件
只需要进行属性变量配置文件中就行
例如我们数据库源的配置就可以写到里面
使用 PropertyPlaceholderConfigurer映射
用于配置文件的管理,
datasource.properties
driver=com.jdbc.mysql.connection
url=jdbc:mysql:localhost:3306
username=root
password=2009
把外部文件引入到Spring配置文件当中去
111加入名称空间
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
222通过context:property-plavehodeer 标签引入外部属性文件
<context:property-placeholder location="datasource.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<property name="url" value="${url}"/>
</bean>
下面事直接配置(不对应,莫怪)下面事加载德鲁伊的连接池

IOC操作Bean管理(基于注解方式)
1、什么是注解 (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..) (2)使用注解,注解作用在类上面,方法上面,属性上面 (3)使用注解目的:简化xml配置
2、Spring针对Bean管理中创建对象提供注解 (1)@Component (2)@Service (3)@Controller (4)@Repository * 上面四个注解功能是一样的,都可以用来创建bean实例
他们只是有 一些默认规则而已:
基于注解方式实现对象的创建
111要引入aop依赖
222开启组件自动扫描
加入context名称空间

33配置扫描路径
<context:component-scan base-package="com.quan.hll"/>
扫描多个包的时候,可以使用逗号隔开:
<context:component-scan base-package="com.quan.hll,com.quan.li"/>
或者直接换成更大的范围
<context:component-scan base-package="com.quan"/>
44累并添加注解
@Component("outpute")
public class OutputE {
@Value("ouputeName")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void pr() {
System.out.println("EEEEEEEEEEEEEEEEeeeeee");
}
}
@Component("hou")
public class HOutputE {
@Autowired
private OutputE outpute;
public OutputE getOutpute() {
return outpute;
}
}
开启组件自动扫描的细节问题
如果我们只是配置下面这个配置文件,spring会将这个路径下的所有累进行扫描一遍
<context:component-scan base-package="com.quan"/>
自动扫描的过滤器
<!-- use-default-filters="false" 不适用默认的过滤器 <context:include-filter 定义需要加入扫描的东西 下面就是只扫描类存在注解为Controller --> <context:component-scan base-package="com.quan.hll" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 处理类的注解为Controller不扫描,其他都要扫描--> <context:component-scan base-package="com.quan.hll" use-default-filters="false"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
基于注解方式实现属性的注入
针对类类型的:
(1)@Autowired:根据属性类型进行自动装配
@Repository public class DaoImpl implements Dao { @Override public void add() { System.out.println("dao add"); } }
service 层
@Service(value = "dService") public class DService { //不需要假set方法 @Autowired private Dao dao; public void add(){ System.out.println("service add..."); dao.add(); } }
test:
public class Main { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml"); DService dService = ac.getBean("dService",DService.class); dService.add(); } }
结果输出为:
service add...
dao add
(2)@Qualifier:根据名称进行注入
这个@Qualifier注解的使用,和上面@Autowired一起使用
因为我们一个接口可能存在多个实现它的类所以这时候我们只是用Autowired来指定是不够的
需要指定bean的名字去注入
@Service(value = "dService") public class DService { //不需要假set方法 @Autowired @Qualifier(value = "daoImpl") private Dao dao; public void add(){ System.out.println("service add..."); dao.add(); } }
(3)@Resource:可以根据类型注入,也可以根据名称注入
@Service(value = "dService") public class DService { // @Resource 什么都不加的时候根据类型注入 @Resource(name = "daoImpl") private Dao dao; public void add(){ System.out.println("service add..."); dao.add(); } }
注意:Resource注解是在import javax.annotation.Resource;就是java扩展包里面的,这个是java的
而@Autowired是在org.springframework.beans.factory.annotation.Autowired;spring内部的
建议使用@Autowired
(4)@Value 注入基本的类型
@Value("quan")
private String name;
@Value("34")
private int age;
完全注解开发
是指用配置类去替代配置文件bean.xml
@Configuration //作为配置类,替代xml配置文件
建立类,并使用注解成为配置类:
@Configuration @ComponentScan(basePackages = {"com.quan.hlll"}) public class SpringConfig { }
加载配置的方式变了,变成了注释方式加载
public class Main { public static void main(String[] args) { //通过配置类加载 ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class); DService dService = ac.getBean("dService",DService.class); dService.add(); } }
其实这个是Spring-boot里面的内容了,
???????
/*
通过java类来加载bean,注解
*/
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HelloConfig {
@Bean(name = "hello")
public Hello hello(){
return new Hello();
}
}
相当于:
<bean id="hello" class="com.quan.hll.javaConfig.Hello" ></bean>
//通过JavaConfig的类对象来获取ApplicationConext
// ApplicationContext ac = new AnnotationConfigApplicationContext(HelloConfig.class);
//通过spring-config.xml配置文件来进行bean加载
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
spring注入日期:
<bean id="sdate" class="com.quan.hll.List.Sdate"> <!-- 使用下面会报错,必须使用格式话进行格式话--> <!-- <property name="date" value="2020-12-20"/>--> <!-- Cannot convert value of type [java.lang.String] to required type --> <!-- [java.util.Date] for property 'date': no matching edit--> <property name="date"> <bean factory-bean="dataFormat" factory-method="parse"> <constructor-arg value="2020-12-20"></constructor-arg> </bean> </property> </bean> <bean id="dataFormat" class="java.text.SimpleDateFormat"> <constructor-arg value="yyyy-MM-dd"/> </bean>
re:Sdate{date=Sun Dec 20 00:00:00 CST 2020}
spring-bean的继承
这里不是在java下创建类去extend而是通过bean的配置文件去实现
主要是bean父设置一个模板或者属性,子bean公用这个属性或者模板
类:
public class BasePlace {
private String place;
private String name;
下面父bean只是共享自己的name的属性值
<bean id="base" class="com.quan.hll.expand.BasePlace" > <property name="name" value="Q"/> </bean> <bean id="expandbase" parent="base"> <property name="place" value="sz"/> </bean>
注意:其实expandbase这个bean也是com.quan.hll.expand.BasePlace类
加入下面的这个bean标签的属性是说明父bean不可被实例化:
<bean id="base" class="com.quan.hll.expand.BasePlace" abstract="true"> 如果调用: BasePlace bb = (BasePlace)ac.getBean("base"); 报错
加入下面一句,子类bean新设置的属性值会覆盖父bean
<property name="name" value="QQ"/>
BasePlace{place='sz', name='Q'}
@Required注解依赖检查,指定类中的属性检查,部分!!!
单单加入这个还是不生效,需要在bean.xml文件里面引入解析注解的bean
适用于bean属性setter方法,并表示受影响的bean属性必须在XML配置文件在配置时进行填充。否则,容器会抛出一个BeanInitializationException异常。
public class BasePlace {
private String place;
private String name;
@Required
public void setName(String name) {
this.name = name;
}
bean。xml
<bean id="base" class="com.quan.hll.expand.BasePlace" > <property name="place" value="ShenZhen"/> </bean>
baocuo
org.springframework.beans.factory.BeanInitializationException:
Property 'name' is required for bean 'base'
注册一个RequiredAnnotationBeanPostProcessor以了解在bean配置文件@Required注解
111
设置context:
<context:annotation-config/>
22设置bean
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
自定义@required注解名字(换名字)
编写注解:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyRequired { }
注册注解:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"> <property name="requiredAnnotationType" value="com.quan.hll.MyRequired"></property> </bean>
使用即可:
public class BasePlace { private String place; private String name; @MyRequired public void setName(String name) { this.name = name; }
多个bean模块化设置配置文件

多个构造函数的歧义
package com.quan.hll.manyConstruntor;
public class MConstructor{
private String name;
private int age;
private String addr;
/*
两个构造函数,可能会出现起义
*/
public MConstructor(int age, String name, String addr) {
this.name = name;
this.age = age;
this.addr = addr;
}
public MConstructor(String name, int age, String addr) {
this.name = name;
this.age = age;
this.addr = addr;
}
@Override
public String toString() {
return "MConstructor{" +
"name='" + name + '\'' +
", age=" + age +
", addr='" + addr + '\'' +
'}';
}
}
/*
第一次没有指定类型出现这个结果:
MConstructor{name='23', age=199, addr='123'}
*/
<!-- 两个构造函数,可能会出现起义-->
<!-- <bean id="mconstructor" class="com.quan.hll.manyConstruntor.MConstructor" >-->
<!-- <constructor-arg >-->
<!-- <value>199</value>-->
<!-- </constructor-arg>-->
<!-- <constructor-arg>-->
<!-- <value>23</value>-->
<!-- </constructor-arg>-->
<!-- <constructor-arg>-->
<!-- <value>123</value>-->
<!-- </constructor-arg>-->
<!-- </bean>-->
<!-- 为构造函数指定的确切数据类型,-->
<bean id="mconstructor" class="com.quan.hll.manyConstruntor.MConstructor" >
<constructor-arg type="java.lang.String" >
<value>199</value>
</constructor-arg>
<constructor-arg type="int">
<value>23</value>
</constructor-arg>
<constructor-arg type="java.lang.String">
<value>123</value>
</constructor-arg>
</bean>
多个配置文件归结到一个配置文件
<import resource="hello-config.xml"/>
<import resource="person-config.xml"/>
SpEL(Spring Expression Language),

浙公网安备 33010602011771号