Spring-IOC

赋值方式

构造器赋值

无参构造器:(利用set方法赋值)

<bean >
    <property name="name" value="zh"/>
    <property name="age" value="33"/>
    <property name="sex">
    <value>男</value>
    </property>
</bean>

有参构造器:

属性名称赋值:
<bean >
     <constructor-arg name="age" value="2"/>
     <constructor-arg name="sex" value="e"/>
     <constructor-arg name="name" value="zh"/>
</bean>
省略name赋值:
<bean >
     <constructor-arg value="2"/>
     <constructor-arg value="e"/>
     <constructor-arg value="zh"/>
</bean>
属性索引赋值:
<bean >
    <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 />

c命名空间赋值(构造方法赋值):

1.配置文件中导入c命名空间:
xmlns:c="http://www.springframework.org/schema/c"
2.使用
<bean />

不同类型属性的赋值:

基本类型直接使用

<property></property>赋值

复杂类型使用标签体

nul值:

<property name="lastName">
    <!--    使用null值(默认不赋值同为null)-->
    <null></null>
</property>

引用类型赋值:

方式一:引用外部bean(地址引用)
<bean >
        <property name="carName" value="宝马"/>
        <property name="color" value="blue"/>
        <property name="price" value="4600"/>
</bean>
<bean >
     <property name="car" ref="car1">
</bean>
方式二:引用内部bean
<bean >
     <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 ></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 >
   <bean ></bean>
     <ref bean="book1"/>
 </util:list>

<bean >
    <property name="maps" ref="map1"/>
    <property name="books" ref="list1"/>
</bean>

bean之间的依赖(改变创建顺序)

<!--depends-on可以改变默认创建顺序-->
<bean />
<bean />

bean的作用域(单实例与多实例)

 scope="singleton" 单实例(默认),容器启动完成之前创建,任何时候获取的都是同一个对象
 scope="prototype" 多实例,在容器中获取时创建,每次获取时都会创建一个新的对象
<bean />
<bean >

工厂模式创建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 >
<constructor-arg value="001"></constructor-arg>
</bean>

实例工厂:

  1. 先配置出实例工厂对象
  2. 配置我们要创建的对象使用哪个工厂创建

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 />
<!--
	factory-bean:指定哪个工厂实例
	factory-method:指定使用工厂实例中的哪个方法
-->
<bean >
	<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 />

创建带有生命周期的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 >

后置处理器(可在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 >
</bean>
<!--无论bean是否有初始化方法,后置处理器都会默认其有-->
<bean ></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 >
    <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:使用构造方法赋值
  1. autowire:default/no(不自动装配)

  2. autowire:byName:按照名字

     		private Car  car:在容器中查找以属性名为id的组件并赋值,找不到就为null
    
  3. autwire:byType:在容器中查找与属性有且只有一个同类型的组件,找不到就为null

  4. 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-IOC

Spring表达式(Spring Expression Language)

在SpEl中使用字面量、
引用其他bean、
引用其他bean的某个属性值、
调用非静态方法、
调用静态方法、
使用运算符
<bean >
    <!--字面量:#{}-->
    <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>