Spring 入门

Spring最的精髓就是依赖注入(DI),bean就是IOC容器管理的对象。

本文主要参考了《Spring教程》、《spring中bean配置和bean注入

本文件所有源码:https://github.com/BuildSoftwareBetter/SpringLessons

0. Spring Bean基础

0.0 bean引用

关键字:ref(spring4.0 以后不再支持 local)
多个xml配置文件和单个xml配置文件都是一样的使用方式。

<!--SystemRole.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="RoleSystem" class="com.david.SL.Role">
        <property name="name">
            <value type="java.lang.String">System</value>
        </property>
    </bean>

    <bean id="RoleAdmin" class="com.david.SL.Role">
        <property name="name" value="Admin"/>
    </bean>

    <!--p模式-->
    <bean id="RoleCommon" class="com.david.SL.Role" p:name="Common"/>
</beans>

<!--SystemUser.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="UserAdmin" class="com.david.SL.User">
        <property name="name" value="AdminUser"/>
        <property name="role">
            <ref local="RoleAdmin"/>
        </property>
    </bean>
</beans>

0.1 依赖注入方式

属性注入:

<!--SystemRole.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="RoleSystem" class="com.david.SL.Role">
        <property name="name">
            <value type="java.lang.String">System</value>
        </property>
    </bean>

    <bean id="RoleAdmin" class="com.david.SL.Role">
        <property name="name" value="Admin"/>
    </bean>

    <!--p模式-->
    <bean id="RoleCommon" class="com.david.SL.Role" p:name="Common"/>
</beans>

注意:p模式需申明xmlns:p=”http://www.springframework.org/schema/p”

构造函数注入:

    <!--构造函数注入-->
    <bean id="helloBeanCons1" class="com.david.SL.HelloWorld">
        <constructor-arg value="name1"/>
    </bean>

   <!--构造函数注入-->
    <bean id="helloBeanCons2" class="com.david.SL.HelloWorld">
        <constructor-arg value="name2" type="java.lang.String"/>
    </bean>

    <!--构造函数注入-->
    <bean id="helloBeanCons3" class="com.david.SL.HelloWorld">
        <constructor-arg>
            <value type="java.lang.String">name3</value>
        </constructor-arg>
    </bean>

注意:当构造函数有重载时,为了防止使用错误的构造函数,务必指定参数类型type的值。

0.2 加载多个配置文件

方法一:

    public static void main(String[] args) {

        // 加载多个xml配置文件
        ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"SystemRole.xml","SystemUser.xml"});

        User user=(User)context.getBean("UserAdmin");

        System.out.println(user.toString());
    }

说明:SystemRole.xml和SystemUser.xml是 0.0 示例中使用的的两个文件。

方法二:
关键字:import
配置文件

<!--SystemAuthority.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resource="SystemRole.xml"/>
    <import resource="SystemUser.xml"/>
</beans>

加载

    public static void main(String[] args) {

        ApplicationContext context=new ClassPathXmlApplicationContext("SystemAuthority.xml");

        User user=(User)context.getBean("UserAdmin");
        System.out.println(user.toString());
    }

0.3 内部bean实例

成员不通过引用进行实例化,而是自定义生成新实例。

    <bean id="UserGuest" class="com.david.SL.User">
        <property name="name" value="Guest1"/>
        <property name="role">
            <!--内部bean实例-->
            <bean class="com.david.SL.Role">
                <property name="name" value="Guest"/>
            </bean>
        </property>
    </bean>

0.4 作用域scope(生命周期)

看到有些地方将spring scope翻译成作用域,是不是翻译成生命周期会准确一些?
scope枚举:
- singleton,单例,全局只有一个此对象,生命周期与应用程序生命周期一致,scope默认为singleton。
- prototype,原型,每次调用getBean都会返回一个新对象,离开作用域后立即失效。

测试一下:
创建Helloworld类:

public class HelloWorld {
    private String name;

    /*属性注入*/
    public void setName(String name) {
        this.name = name;
    }

    public void printHello() {
        System.out.println("Spring :Hello " + name);
    }
}

xml配置文件:

<!--applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="helloBeanSig" class="com.david.SL.HelloWorld">
        <property name="name" value="SingletonBean"/>
    </bean>

    <bean id="helloBeanPro" class="com.david.SL.HelloWorld" scope="prototype">
        <property name="name" value="PrototypeBean"/>
    </bean>

</beans>

测试:

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        HelloWorld single = (HelloWorld) context.getBean("helloBeanSig");
        single.printHello();
        single.setName("single2");

        HelloWorld single2 = (HelloWorld) context.getBean("helloBeanSig");
        single2.printHello();

        HelloWorld proto = (HelloWorld) context.getBean("helloBeanPro");
        proto.printHello();
        proto.setName("proto2");

        HelloWorld proto2 = (HelloWorld) context.getBean("helloBeanPro");
        proto2.printHello();
    }

这里写图片描述
第一个(默认scope=”singleton”)修改后再次getBean为修改后的值,第二个(scope=”prototype”)修改后不生效。

0.5 集合类型注入

不想写了,参考:Spring集合 (List,Set,Map,Properties) 实例

0.6 注入日期到bean

先写一种方法:

    <!--注入时间,FactoryBean 方式-->
    <bean id="dateFormat" class="java.text.SimpleDateFormat">
        <constructor-arg value="yyyy/MM/dd"/>
    </bean>
    <bean id="HelloWorldFactoryBeanCreateTime" class="com.david.SL.HelloWorld">
        <property name="createTime">
            <bean factory-bean="dateFormat" factory-method="parse">
                <constructor-arg value="2018/07/07"/>
            </bean>
        </property>
    </bean>

0.7 Spring PropertyPlaceholderConfigurer实例

新建properties文件,(IDEA新建方式:src右键=>Resource Bundle)。

# database.properties
jdbc.url=jdbc:mysql://localhost:3306/test_db

xml文件引用:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location">
            <value>database.properties</value>
        </property>
    </bean>

    <bean id="HelloWorldPlaceholder" class="com.david.SL.HelloWorld">
        <property name="name" value="${jdbc.url}"/>
    </bean>

0.8 配置继承

<?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,可以被实例化-->
    <bean id="ChinaCustomer" class="com.david.SL.Customer">
        <property name="country" value="China"/>
    </bean>

    <!--继承-->
    <bean id="xiaoming" class="com.david.SL.Customer" parent="ChinaCustomer">
        <property name="name" value="XiaoMing"/>
    </bean>

    <!--继承,并覆盖属性值-->
    <bean id="xiaoli" class="com.david.SL.Customer" parent="ChinaCustomer">
        <property name="name" value="XiaoLi"/>
        <!--覆盖-->
        <property name="country" value="Japen"/>
    </bean>

    <!--抽象bean,不可以被实例化-->
    <bean id="ChinaCustomerAbstract" class="com.david.SL.Customer" abstract="true">
        <property name="country" value="China"/>
    </bean>

    <!--继承抽象类-->
    <bean id="lisi" class="com.david.SL.Customer" parent="ChinaCustomerAbstract">
        <property name="name" value="LiSi"/>
    </bean>

    <!--模板,不指定类型-->
    <bean id="CountryTemplate" abstract="true">
        <property name="country" value="China"/>
    </bean>

    <!--继承模板-->
    <bean id="zhangsan" class="com.david.SL.Customer" parent="CountryTemplate">
        <property name="name" value="ZhangSan"/>
    </bean>
</beans>

0.9 依赖检查

关键字:@Required
确保特定属性已经设置:

public class Customer 
{
    private Person person;
    private int type;
    private String action;

    public Person getPerson() {
        return person;
    }
    // 必须为person属性注入对象,否则将抛出异常
    @Required
    public void setPerson(Person person) {
        this.person = person;
    }
}

在基于注解中使用:

@Component
public class Customer 
{
    private Person person;
    private int type;
    private String action;

    public Person getPerson() {
        return person;
    }
    // 必须为person属性注入对象,否则将抛出异常
    @Autowired(required=true)
    public void setPerson(Person person) {
        this.person = person;
    }
}

除了使用@Required进行注解,我们还可以自定义同等功能的注解(是否可以称为取别名?),参考:《Spring自定义@Required-style注解

0.10 bean初始化和销毁接口

关键字:InitializingBean、init-method、DisposableBean、destroy-method、@PostConstruct、@PreDestroy

初始化在Spring中有两种方式:

  • 实现InitializingBean接口
  • 在配置中指定init-method方法

销毁在Spring中的两种方式:

  • 实现DisposableBean接口
  • 在配置中指定destroy-method方法

在上面强调了在Spring中,是因为J2EE库(common-annotations.jar)中也有方法可以实现相同的功能。
使用方式:在方法上注解@PostConstruct、@PreDestroy,再将(需申明xmlns:context=”http://www.springframework.org/schema/context”)或配置到xml配置文件中。

代码:

// Customer.java
public class Customer {
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;

    private String country;

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String toString() {
        return ("Country " + this.country + ", Name " + this.name);
    }

    @PostConstruct
    public void initIt() throws Exception {
        System.out.println("Init method after properties are set : ");
    }

    @PreDestroy
    public void cleanUp() throws Exception {
        System.out.println("Spring Container is destroy! Customer clean up");
    }
}

配置文件:

<!--CustomerConfig.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"
       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">

    <!--不添加此代码将不会生效,context需申明xmlns:context="http://www.springframework.org/schema/context"-->
    <!--<context:annotation-config />-->

    <!--或者添加此代码-->
    <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

    <bean id="xiaoming" class="com.david.SL.Customer" parent="ChinaCustomer">
        <property name="name" value="XiaoMing"/>
    </bean>
</beans>

测试:

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("CustomerConfig.xml");

        Customer c = (Customer) context.getBean("xiaoming");

        System.out.println(c.getName());

        ((ClassPathXmlApplicationContext) context).close();
    }

Init method after properties are set :
XiaoMing
Spring Container is destroy! Customer clean up


1. bean配置方式

  1. xml配置
  2. 基于注解
  3. JavaConfig类定义

2. 依赖注入方式

  1. 属性注入
  2. 构造函数注入
  3. 工厂方式注入

3. Spring表达式语言(Spring EL)

Spring表达式可以通过xml和注解使用。

xml 中使用EL

bean代码:

// Book.java
package com.david.SL;

public class Book {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // EL需要使用的属性必须是public,否则会抛出异常
    public String name;

    public String getFullName(String prefix){
        return prefix+this.name;
    }
}

// BookDetail.java
package com.david.SL;

public class BookDetail {

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }

    private Book book;

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    private String bookName;

    @Override
    public String toString()    {
        return this.bookName;
    }
}

配置:

<?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 id="bookBean" class="com.david.SL.Book">

        <!--普通属性设置-->
        <!--<property name="name" value="Computer Networking"/>-->

        <!--使用EL,并调用String的toUpperCase()方法设置属性-->
        <property name="name" value="#{'Computer Networking'.toUpperCase()}"/>
    </bean>

    <bean id="bookDetail" class="com.david.SL.BookDetail">
        <property name="book" value="#{bookBean}"/>

        <!--使用EL并使用bean对象的属性设置属性值-->
        <!--<property name="bookName" value="#{bookBean.name}"/>-->

        <!--使用EL并调用bean对象的无参方法设置属性值-->
        <property name="bookName" value="#{bookBean.getName()}"/>

        <!--使用EL并调用bean对象的有参方法设置属性值-->
        <!--<property name="bookName" value="#{bookBean.getFullName('v1.0 ')}"/>-->
    </bean>

</beans>

测试:

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("BookELConfig.xml");
        BookDetail bd = (BookDetail)context.getBean("bookDetail");
        System.out.println(bd.toString());

    }

注解方式使用EL

bean代码及注解:

// Book.java
package com.david.SL;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

// 注解设置自动扫描组件,并设置组件名称
@Component("bookBean")
public class Book {

    public String getName() {
        return name;
    }

    // 注解设置属性值
    @Value("Computer Networking")
    public String name;

    // 注解设置属性,使用String运算符toUpperCase()
    //@Value("#{'Computer Networking'.toUpperCase()}")
    //public String name;

    public String getFullName(String prefix){
        return prefix+this.name;
    }
}

// BookDetail.java
package com.david.SL;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

// 注解设置自动扫描组件,并设置组件名称
@Component("bookDetail")
public class BookDetail {

    // 使用EL设置属性值
    @Value("#{bookBean}")
    private Book book;

    // 使用EL设置属性值
    @Value("#{bookBean.name}")
    private String bookName;

    // 使用EL设置属性值,通过函数
    //@Value("#{bookBean.getName()}")
    //private String bookName;

    // 使用EL设置属性值,通过带参数的函数
    //@Value("#{bookBean.getFullName('v1.0 ')}")
    //private String bookName;

    @Override
    public String toString()    {
        return this.bookName;
    }
}

配置自动扫描:

<!--AutoScanConfig.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: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">

    <context:component-scan base-package="com.david.SL">

        <context:include-filter type="regex" expression="com.david.SL.Book*"/>
    </context:component-scan>
</beans>

测试:

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("AutoScanConfig.xml");
        BookDetail bd = (BookDetail)context.getBean("bookDetail");
        System.out.println(bd.toString());

    }

EL运算符

基本运算符

Spring EL支持大多数标准的属性、逻辑和关系运算符。

  • 关系运算符 – 等于 (==, eq), 不等于 (!=, ne), 小于 (<, lt), 小于或等于 (<= , le), 大于 (>, gt), 和大于或等于 (>=, ge).
  • 逻辑运算符 – 且, 或, 非 (!).
  • 数学运算符 – 加法(+), 减法 (-), 乘法 (*), 除法(/), 除模(%) 和指数幂 (^).

详细可参考《Spring EL运算符实例

三元运算符

EL也支持三元运算符,例如:

    @Value("#{10 < 100 ? true : false}")
    private boolean warning;
List和Map

EL支持Lists和Maps实例,例如:

//在bookMap中查找为key = 'Math'的Book
@Value("#{booksBean.bookMap['Math']}")
private Book Math;

//返回booksList中第一个对象
@Value("#{booksBean.bookList[0]}")
private Book book;
正则表达式
@Value("#{'100' matches '\\d+' }")
private boolean isDigit;

ExpressionParser

EL解析器,可以及解析EL语法,并通过getVaue获得语法的返回值。
详细参考《测试 Spring EL与ExpressionParser

4. Spring自动组件扫描

在之前的配置中需要手动配置每个bean组件太繁琐了,现在我们尝试自动扫描的方式来使用bean组件。在组件上添加自动扫描注解,并配置在系统xml配置中添加context:component-scan配置即可实现自动扫描,并可实现自动装配。

在Spring2.5中,有4种类型的组件自动扫描注解类型:

  • @Component – 指示自动扫描组件。
  • @Repository – 表示在持久层DAO组件。
  • @Service – 表示在业务层服务组件。
  • @Controller – 表示在表示层控制器组件。

因此,使用哪一个?其实并不那么重要。参见 @Repository,@Service 或 @Controller 源代码。你可能会发现,所有的 @Repository, @Service 或 @Controller 被注解为 @Component。因此,我们可以只使用 @Component 对所有组件进行自动扫描?是的,Spring会自动扫描所有组件的 @Component 注解。它工作正常,但不是一个好的做法,为便于阅读,应该始终声明@Repository,@ Service 或 @Controller 在指定的层,使你的代码更易于阅读。

下面直接上代码:
两个bean组件:

// CustomerDAO.java
package com.david.SL.AutoScan;

import org.springframework.stereotype.Component;

// 注解为自动扫描组件
@Component
public class CustomerDAO {

    @Override
    public String toString(){
        return "this is a CustomerDAO";
    }
}

// CustomerService.java
package com.david.SL.AutoScan;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

// 注解为自动扫描组件
@Component
public class CustomerService {

    // Autowired实现自动装配
    @Autowired
    private CustomerDAO customerDAO;

    @Override
    public String toString() {
        return "CustomerService [customerDAO=" + customerDAO + "]";
    }
}

写配置文件:
*注意:需要申明xmlns:context=”http://www.springframework.org/schema/context”,同时xsi:schemaLocation也需添加http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd两项*

<?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: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">

    <context:component-scan base-package="com.david.SL.AutoScan"/>
</beans>

测试:
注意:默认情况下,Spring 将小写组件的第一字符设为组件名称

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("AutoScanConfig.xml");

        // 默认情况下,Spring 将小写组件的第一字符设为组件名称- CustomerService组件在Spring中的名称为到'customerService'。
        CustomerService cs= (CustomerService) context.getBean("customerService");

        System.out.println(cs.toString());

    }

也可以自定义组件名称:

@Component("CustomerServiceA")
public class CustomerService {
    /***/
}

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("AutoScanConfig.xml");

        CustomerService cs= (CustomerService) context.getBean("CustomerServiceA");

        System.out.println(cs.toString());

    }

过滤组件-包含
关键字:context:include-filter
为了更精准的扫描包内组件,可以设置过滤器进行精准匹配:

    <context:component-scan base-package="com.david.SL">
        <!--type="regex" 匹配正则表达式-->
        <context:include-filter type="regex" expression="com.david.SL.AutoScan.*"/>
    </context:component-scan>

type 有多种类型,其他类型可不一一列举了

过滤组件-不包含
关键字:context:exclude-filter

    <context:component-scan base-package="com.david.SL">
        <!--type="regex" 匹配正则表达式-->
        <context:exclude-filter type="regex" expression="com.david.SL.AutoScan.*"/>
    </context:component-scan>

@Qualifier 限定组件名称

如果容器中有一个以上匹配的Bean时,则可以通过@Qualifier注解限定Bean的名称,如下所示:

package com.david.SL.AutoScan;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class CustomerService {

    // @Qualifier指定bean组件的名称
    @Autowired
    @Qualifier("CustomerDAOA")
    private CustomerDAO customerDAO;

    @Override
    public String toString() {
        return "CustomerService [customerDAO=" + customerDAO + "]";
    }
}

5. 自动装配Bean

关键字:autowire

在Spring中,支持 5 自动装配模式(Spring3以后只有4种,autodetect被废弃):

  • no – 缺省情况下,自动配置是通过“ref”属性手动设定。
  • byName – 根据属性名称自动装配。如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。
  • byType – 按数据类型自动装配。如果一个bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它。若有两个及以上相同类型bean组件对象将会抛出异常。
  • constructor – 在构造函数参数的byType方式。
  • autodetect – 如果找到默认的构造函数,使用“自动装配用构造”; 否则,使用“按类型自动装配”【在Spring3.0以后的版本被废弃,已经不再合法了】。

以下demo的使用的User和Role的代码如下:

// Role.java
package com.david.SL;

public class Role {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

// User.java
package com.david.SL;

public class User {

    public User(){

    }

    public User(Role role){
        this.role=role;
    }


    private String name;

    public void setName(String name) {
        this.name = name;
    }

    private Role role;

    public void setRole(Role role) {
        this.role = role;
    }

    public String toString() {
        return "Name = " + this.name + ",Role " + this.role.getName();
    }
}

全部配置:

<!--AutoWireConfig.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="RoleAdmin" class="com.david.SL.Role">
        <property name="name" value="Admin"/>
    </bean>

    <!--有两个Role类的bean时,byType方式自动装配将抛出异常-->
    <!--<bean id="RoleSystem" class="com.david.SL.Role">-->
    <!--<property name="name">-->
    <!--<value type="java.lang.String">System</value>-->
    <!--</property>-->
    <!--</bean>-->

    <!--自动装配-->

    <!--no 默认装配方式,使用ref-->
    <!--<bean id="UserAdminDefault" class="com.david.SL.User">-->
        <!--<property name="name" value="UserAdminDefault"/>-->
        <!--<property name="role">-->
            <!--<ref bean="RoleAdmin"/>-->
        <!--</property>-->
    <!--</bean>-->

    <!--byType-->
    <!--<bean id="UserAdminByType" class="com.david.SL.User" autowire="byType">-->
        <!--<property name="name" value="UserAdminByType"/>-->
    <!--</bean>-->

    <!--byName-->
    <!--<bean id="UserAdminByName" class="com.david.SL.User" autowire="byName">-->
        <!--<property name="name" value="UserAdminByName"/>-->
    <!--</bean>-->
    <bean id="role2" class="com.david.SL.Role">
        <property name="name" value="AdminRole"/>
    </bean>

    <!--constructor-->
    <bean id="UserAdminByConstructor" class="com.david.SL.User" autowire="constructor">
        <property name="name" value="UserAdminByConstructor"/>
    </bean>
</beans>

测试代码:

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("AutoWireConfig.xml");

        // no
//        User UserAdminDefault = (User) context.getBean("UserAdminDefault");
//        System.out.println(UserAdminDefault.toString());


        // byType
//        User UserAdminByType = (User) context.getBean("UserAdminByType");
//        System.out.println(UserAdminByType.toString());

        // byName
//        User UserAdminByName = (User) context.getBean("UserAdminByName");
//        System.out.println(UserAdminByName.toString());

        // constructor
        User UserAdminByConstructor = (User) context.getBean("UserAdminByConstructor");
        System.out.println(UserAdminByConstructor.toString());

    }

no

默认方式,使用ref手动设定。
xml配置:

    <bean id="RoleAdmin" class="com.david.SL.Role">
        <property name="name" value="Admin"/>
    </bean>

    <!--no 默认装配方式,使用ref-->
    <bean id="UserAdminDefault" class="com.david.SL.User">
        <property name="name" value="UserAdminDefault"/>
        <property name="role">
            <ref bean="RoleAdmin"/>
        </property>
    </bean>

byType

    <bean id="RoleAdmin" class="com.david.SL.Role">
        <property name="name" value="Admin"/>
    </bean>

    <!--有两个Role类的bean时,byType方式自动装配将抛出异常-->
    <!--<bean id="RoleSystem" class="com.david.SL.Role">-->
    <!--<property name="name">-->
    <!--<value type="java.lang.String">System</value>-->
    <!--</property>-->
    <!--</bean>-->

    <!--自动装配-->

    <!--byType-->
    <bean id="UserAdminByType" class="com.david.SL.User" autowire="byType">
        <property name="name" value="UserAdminByType"/>
    </bean>

byName

必须是完全相同的名称:

    <!--byName-->
    <bean id="UserAdminByName" class="com.david.SL.User" autowire="byName">
        <property name="name" value="UserAdminByName"/>
    </bean>
    <!--User中有Role类型的role属性-->
    <bean id="role" class="com.david.SL.Role">
        <property name="name" value="Admin"/>
    </bean>

constructor

配置:

    <bean id="RoleAdmin" class="com.david.SL.Role">
        <property name="name" value="Admin"/>
    </bean>

    <bean id="UserAdminByConstructor" class="com.david.SL.User" autowire="constructor">
        <property name="name" value="UserAdminByConstructor"/>
    </bean>

输出结果:

Name = UserAdminByConstructor,Role Admin

上面的代码是可以运行的,如果有两个Role类型的bean组件会是什么情况:

    <bean id="RoleAdmin" class="com.david.SL.Role">
        <property name="name" value="Admin"/>
    </bean>

    <!--将会使用此bean组件,因为User构造函数的参数名为role-->
    <bean id="role" class="com.david.SL.Role">
        <property name="name" value="AdminRole"/>
    </bean>

    <bean id="UserAdminByConstructor" class="com.david.SL.User" autowire="constructor">
        <property name="name" value="UserAdminByConstructor"/>
    </bean>

输出结果:

Name = UserAdminByConstructor,Role AdminRole

说明使用的是id=”role”的bean组件。由此可以推断,构造函数自动装配将首先查找同类型组件,然后在所有同类型组件中查找与参数同名的组件进行装配。还有一种情况,有多个与构造函数参数同类型的组件,但是没有同名的组件将会是什么情况?测试的结果是将不会装配

6. Spring AOP(面向方面编程)

Advice

AOP是一个对象中函数过程的拦截器。AOP可以劫持一个正在执行的方法,在方法执行前、执行后、抛出异常后等时间点添加额外的功能。
在Spring AOP中有4种类型通知(Advice):

  • MethodBeforeAdvice 方法执行之前通知
  • AfterReturningAdvice 方法返回之后通知
  • ThrowsAdvice 抛出异常之后通知
  • MethodInterceptor 环绕通知,结合了上面的三个通知,必须调用methodInvocation.proceed()执行原方法。

Pointcut、Advisor

Advice会拦截对象的所有方法,但是通常情况我们需要拦截某一特定的方法或一类方法,所以Advice并不适用。接下来引入Pointcut。
关键字:NameMatchMethodPointcut、RegexpMethodPointcutAdvisor

  • NameMatchMethodPointcut,匹配名称
  • RegexpMethodPointcutAdvisor,正则表达式匹配
    <bean class="org.springframework.aop.support.NameMatchMethodPointcut">
        <!--匹配名称为run的方法-->
        <property name="mappedName" value="run"/>
    </bean>
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--匹配方法中含run字符串的方法-->
        <property name="pattern" value=".*run.*"/>
    </bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值