Spring-IOC
目录
赋值方式
构造器赋值
无参构造器:(利用set方法赋值)
<bean id="p1" class="com.zh.pojo.Person">
<property name="name" value="zh"/>
<property name="age" value="33"/>
<property name="sex">
<value>男</value>
</property>
</bean>
有参构造器:
属性名称赋值:
<bean id="p2" class="com.zh.pojo.Person">
<constructor-arg name="age" value="2"/>
<constructor-arg name="sex" value="e"/>
<constructor-arg name="name" value="zh"/>
</bean>
省略name赋值:
<bean id="p3" class="com.zh.pojo.Person">
<constructor-arg value="2"/>
<constructor-arg value="e"/>
<constructor-arg value="zh"/>
</bean>
属性索引赋值:
<bean id="p3" class="com.zh.pojo.Person">
<constructor-arg index="0" value="你好"/>
<!--重载情况下,type可以指定参数类型
Person(String name, String sex, String email)
Person(String name, Integer age,String sex)
-->
<constructor-arg index="1" type="java.lang.Integer" value="23"/>
<constructor-arg index="2" value="ec"/>
</bean>
p命名空间赋值(set方法赋值):
1.配置文件中导入p命名空间
xmlns:p="http://www.springframework.org/schema/p"
2.使用
<bean id="person04" class="com.zh.pojo.Person" p:age="12" p:sex="男" p:name="zh"/>
c命名空间赋值(构造方法赋值):
1.配置文件中导入c命名空间:
xmlns:c="http://www.springframework.org/schema/c"
2.使用
<bean id="person05" class="com.zh.pojo.Person"c:age="13" c:sex="nv" c:name="zhs" c:email="33@qq.com"/>
不同类型属性的赋值:
基本类型直接使用
<property></property>赋值
复杂类型使用标签体
nul值:
<property name="lastName">
<!-- 使用null值(默认不赋值同为null)-->
<null></null>
</property>
引用类型赋值:
方式一:引用外部bean(地址引用)
<bean id="car1" class="com.zh.pojo.Car">
<property name="carName" value="宝马"/>
<property name="color" value="blue"/>
<property name="price" value="4600"/>
</bean>
<bean id="p1" class="com.zh.pojo.Person">
<property name="car" ref="car1">
</bean>
方式二:引用内部bean
<bean id="p1" class="com.zh.pojo.Person">
<property name="car">
<bean class="com.zh.pojo.Car">
<property name="carName" value="宝马"/>
<property name="color" value="blueS"/>
<property name="price" value="100000"/>
</bean>
</bean>
List赋值:
<property name="books">
<!--books=new ArrayList<Book>()-->
<list>
<bean id="book2" class="com.zh.pojo.Book" p:bookName="西游记" p:author="吴承恩"></bean>
<!-- 引用外部bean-->
<ref bean="book1"/>
</list>
</property>
map赋值:
<property name="maps">
<!--maps=new HashMap()-->
<map>
<!--每个entry代表一个键值对-->
<entry key="key01" value="zh"></entry>
<entry key="key02" value="12"></entry>
<entry key="key03" value-ref="book1"></entry>
<entry key="key04">
<bean class="com.zh.pojo.Car">
<properties name="carName" value="法拉利"> </properties>
</bean>
</entry> <
</map>
</property>
Properties赋值:
<property name="properties">
<!--properties=new Properties(),k、v都是String-->
<props>
<prop key="userName">root</prop>
<prop key="passWord">zh1234</prop>
<prop key="link">www.person.top</prop>
</props>
</property>
util命名空间:
<!--util命名空间创建集合类型的bean 全局可复用-->
<util:map>
<entry key="key01" value="q"/>
<entry key="key02" value="w"/>
<entry key="key03" value-ref="book1"/>
<entry key="key04">
<bean class="com.zh.pojo.Car">
<property name="carName">
<value>玛莎拉蒂</value>
</property>
</bean>
</entry>
</util:map>
<util:list id="list1">
<bean id="book2" class="com.zh.pojo.Book" p:bookName="西游记" p:author="吴承恩"></bean>
<ref bean="book1"/>
</util:list>
<bean id="p2" class="com.zh.pojo.Person">
<property name="maps" ref="map1"/>
<property name="books" ref="list1"/>
</bean>
bean之间的依赖(改变创建顺序)
<!--depends-on可以改变默认创建顺序-->
<bean id="car" class="com.zh.pojo.Car" depends-on="p1,b1"/><bean id="p1" class="com.zh.pojo.Person"/>
<bean id="b1" class="com.zh.poj.Book"/>
bean的作用域(单实例与多实例)
scope="singleton" 单实例(默认),容器启动完成之前创建,任何时候获取的都是同一个对象
scope="prototype" 多实例,在容器中获取时创建,每次获取时都会创建一个新的对象
<bean id="p1" class="com.zh.pojo.Person" scope="singleton"/>
<bean id="p1" class="com.zh.pojo.Person" scope="prototype">
工厂模式创建bean:
bean的创建默认就是框架利用反射new出来的实例
工厂模式:工厂帮我们创建对象,专门帮我们创建对象的类就是工厂
pojo
package com.zh.pojo;
public class AirPlane {
private String fdj;
private String length;
private String personNum;
private String jzName;
private String fjsName;
}
静态工厂创建:
(不需要创建工厂本身,通过类名.静态方法直接调用)
AirplaneStaticFactory:
package com.zh.Factory;
import com.zh.pojo.AirPlane;
@Data
@NoArgsConstructo
@AllArgsConstructor
public class AirplaneStaticFactory {
private static AirPlane getAirplane(String jzName){
System.out.println("静态工厂创建");
AirPlane airPlane = new AirPlane();
airPlane.setFdj("天行");
airPlane.setFjsName("zhs");
airPlane.setJzName(jzName);
airPlane.setLength("12.3m");
airPlane.setPersonNum("8909090");
return airPlane;
}
}
在容器中注册
<!--
class:静态工厂全类名
factory-method:指定工厂方法
constructor-arg:给方法传参
-->
<bean id="airPlane1" class="com.zh.Factory.AirplaneStaticFactory" factory-method="getAirplane">
<constructor-arg value="001"></constructor-arg>
</bean>
实例工厂:
- 先配置出实例工厂对象
- 配置我们要创建的对象使用哪个工厂创建
AirplaneInstanceFactory:
package com.zh.Factory;
import com.zh.pojo.AirPlane;
public class AirplaneInstanceFactory {
private AirPlane getAirplane(String jzName){
System.out.println("实例工厂创建");
AirPlane airPlane = new AirPlane("22","ff","2f",jzName,"zhs");
return airPlane;
}
}
在容器中注册:
<bean id="instanceFactory" class="com.zh.Factory.AirplaneInstanceFactory"/>
<!--
factory-bean:指定哪个工厂实例
factory-method:指定使用工厂实例中的哪个方法
-->
<bean id="airPlane2" class="com.zh.pojoj.AirPlane" factory-bean="instanceFactory" factory-method="getAirplane">
<consturctor-arg value="002"></consturctor-arg>
</bean>
FactoryBean(Spring中规定的一个接口)
只要这个接口的实现类,Spring都认为是一个工厂
1.ioc容器启动的时候不会创建实例
2.FactoryBean:容器中获取时才会创建对象
MyFactoryBeanImplement
/**
* 实现了FactoryBean接口的类是Spring可以认识的工厂类
* Spring会自动的调用工厂方法创建实例
* 1.编写一个FactoryBean的实现类
* 2.在spring配置文件中 进行注册
*/
public class MyFactoryBeanImplement implements FactoryBean<AirPlane> {
public MyFactoryBeanImplement() {
super();
}
/**
* getObject:工厂方法,返回创建的对象
*/
public AirPlane getObject() throws Exception {
System.out.println("FactoryBean创建对象");
AirPlane airPlane = new AirPlane("22", "ff", "2f", UUID.randomUUID().toString(), "zhs");
return airPlane;
}
/**
* 返回创建的对象类型
* spring会自动调用这个方法来确认创建的对象类型
*
*/
public Class<?> getObjectType() {
// System.out.println("FactoryBean创建对象2");
// return AirPlane.class;
return null;
}
/**
* 创建的对象是否为单例
*
* @return
*/
public boolean isSingleton() {
// System.out.println("FactoryBean创建对象3");
return true;
}
}
在容器中注册:
<bean id="myFactoryBean" class="com.zh.Factory.MyFactoryBeanImplement"/>
创建带有生命周期的bean:
bean的生命周期:bean的创建到销毁
ioc容器中注册的bean:
1).单实例bean,容器启动的时候创建完成,容器关闭时销毁
2).多实例bean,获取的时候才会创建
我们可以为bean自定义一些生命周期方法,Spring在创建或销毁时就会调用指定方法
单实例:bean的生命周期
(容器启动)构造器====>初始化方法====>(容器关闭)销毁方法
多实例:获取bean(构造器====>初始化方法=====>容器关闭不会调用bean的销毁方法)
后置处理器:
(容器启动)构造器=====>后置处理器before====>初始化方法=====>后置处理器after=======>bean初始化完成
自定义生命周期方法:
Book.java
public void destory() {
System.out.println("销毁了");
}
public void init() {
System.out.println("初始化");
}
使用:
<bean id="book1" class="com.zh.pojo.Book" destroy-method="destory" init-method="init">
后置处理器(可在bean初始化前后调用方法)
1.实现接口
public class MyBeanPostProcessor implements BeanPostProcessor {
// 初始化之前调用
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "bean将要调用初始化方法l......BeforeInitialization");
return bean;
}
/*
初始化完成之后调用
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "bean初始化方法调用完了.....AfterInitialization");
return bean;
}
}
2.在容器中注册
<bean id="MyBeanPostProcessor" class="com.zh.pojo.MyBeanPostProcessor">
</bean>
<!--无论bean是否有初始化方法,后置处理器都会默认其有-->
<bean id="car" class="com.zh.pojo.Car"></bean>
Spring管理连接池
将数据库连接池作为单实例是最好的,一个项目就是一个连接池,
连接池里管理很多连接,连接是直接从连接池中拿
可以让Spring帮我们创建连接池对象,(管理连接池)
db.properties:
user=root
pwd=zh123456
url=jdbc:mysql://localhost:3306/mybatis
driver=com.mysql.cj.jdbc.Driver
容器中注册数据源组件:
<!--
加载外部配置文件(依赖context命名空间) 固定写法classpath:表示引用类路径下的一个资源
-->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"/>
<property name="password" value= "${pwd}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="driverClass" value="${driver}"/>
</bean>
Test
@Test
public void TestConnectPool() throws SQLException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config4.xml");
// 根据类型获取组件时,可以获取到这个类型下的所有实现类子类等等
DataSource dataSource = context.getBean(DataSource.class);
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
基于xml的自动装配(自动赋值):
自动装配只用于自定义类型的属性
byName和byType都是使用set方法赋值
constructor:使用构造方法赋值
-
autowire:default/no(不自动装配)
-
autowire:byName:按照名字
private Car car:在容器中查找以属性名为id的组件并赋值,找不到就为null
-
autwire:byType:在容器中查找与属性有且只有一个同类型的组件,找不到就为null
-
autowire:constructor:
public Person(Car car)
按照构造方法赋值:
1.先按照有参构造器参数的类型进行装配,没有就为null
2.如果按照类型找到了多个,在根据byName进行查找,找到就装配,找不到就null
通过注解配置组件:
通过注解,可以快速的将这个组件添加到ioc容器中
@Controller:控制器,建议控制器层(controller包下)组件使用
@Service:业务逻辑,建议service包下组件使用
@Repository:dao层下组件使用
@Component:给其他组件使用
(四个注解都可以使用,为了便于维护,建议分类使用)
使用注解将组件快速添加到容器步骤:
1.给要添加的组件上添加注解(四个中任何一个)
2.配置自动包扫描,自动扫描添加了注解的组件(依赖context命名空间)
3.一定要导入aop包(idea自动导入context下要使用的包)
使用注解加入到容器中的组件,和使用配置加入到容器中的组件行为是一样的
1.组件的id.默认就是组件的列名首字母小写
@Service("bookServiceZh")
2.组件的作用域,默认就是单例的
@Scope(value = "prototype")
context:exclude-filter:指定包扫描是不包含的类
*type=“annotation”:指定排除规则,排除使用了指定注解的组件
expression=“注解全类名“
*type="assignable":指定排除某个具体的类,按照类排除
expression=“类的全类名”
【aspectj(aspectj表达式)、custom(自定义一个TypeFilter,自己写代码决定哪些使用)、regex(正则表达式)】
<context:component-scan base-package="com.zh" use-default-filters="false">
<context:exclude-filter type="assignable" expression="com.zh.dao.BookDao"/>
</context:component-scan>
context:include-filter:指定包扫描只包含的类
包扫描时,默认将有注解的组件全部扫描进来
user-default-filters:禁用默认规则,只保留哪些
<context:component-scan base-package="com.zh" use-default-filters="false">
<context:include-filter type="assignable" expression="com.zh.dao.BookDao"/>
</context:component-scan>
@AutoWired自动装配
@AutoWired原理:
@AutoWired
private BookService bookService;
1.先按照类型去容器中找到相应的组件;bookService=ioc.getBean(BookService.class)
2.没找到,报错
3.找到多个
按照变量名作为id继续匹配,BookService,BookServiceExt
如果找不到报错,可以使用@Qualifier指定id名(在自动装配找到同类型多个时,默认以属性为id继续查找)
@AutoWired标注的自动装配的属性默认是一定要装配的
@AutoWired(require=false)指定属性不能自动装配时,为null
@AutoWired、@Resource区别:
@AutoWired、@Resource、@Inject:都可以用于自动装配,区别:
@AutoWired:最强大,只能用于Spring容器
@Resource:java标准,扩展性更强,也适用于其他容器框架(EJB)
@Inject:EJB
执行顺序不同:@Autowired默认通过bytype的方式实现。而且必须要有这个对象
@Resource默认通过byname的方式实现
方法上使用@AutoWired
/**
* 方法上使用@AutoWired:
* 1)这个方法会在bean创建时自动运行
* 2)这个方法上的每个参数都会自动注入值(引用类型)
*/
@Autowired
// @Resource
public void doGet2(@Qualifier("bookServiceExt") BookService bookService, BookDao bookDao){
System.out.println("spring启动了这个方法"+bookService+"===>"+bookDao);
}
泛型依赖注入:
Spring表达式(Spring Expression Language)
在SpEl中使用字面量、
引用其他bean、
引用其他bean的某个属性值、
调用非静态方法、
调用静态方法、
使用运算符
<bean id="p2" class="com.zh.pojo.Person">
<!--字面量:#{}-->
<property name="salary" value="#{12*43}"/>
<!-- 引用其他bean的某个属性值-->
<property name="lastName" value="#{car1.carName}"/>
<!-- 引用其他bean-->
<property name="car" value="#{car1}"/>
<!-- 调用静态方法:#{T(全类名).静态方法名()}-->
<property name="email" value="#{T(java.util.UUID).randomUUID().toString()}"/>
<!--调用非静态方法:对象.方法名-->
<property name="gender" value="#{car1.getCarName()}"/>
</bean>