开启注解扫描

applicationContext.xml中需要开启注解扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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.example.bean.demo"/>

</beans>

使用注解定义Bean

  • Spring2.5引入使用注解去定义Bean
    • @Component 描述Spring框架中Bean
  • 除了@Component外,Spring提供了3个功能基本和@Component等效的注解
    • @Repository 用于对DAO实现类进行标注
    • @Service 用于Service实现类进行标注
    • @Controller 用于对Controller实现类进行标注
  • 这三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强
  1. 编写类,并使用@Component注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package com.example.bean.demo;

    import org.springframework.stereotype.Component;

    /**
    * Spring的Bean管理的注解方式:
    * - 传统方式需要去XML配置<bean id="" class=""><bean/>
    *
    * @author jinglv
    * @date 2021/01/22
    */
    @Component("userService")
    public class UserService {
    public String sayHello(String name) {
    return "Hello:" + name;
    }
    }
  2. 测试类,并执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.example.bean.demo;

    import org.junit.jupiter.api.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    /**
    * @author jinglv
    * @date 2021/01/22
    */
    class UserServiceTest {

    @Test
    void sayHello() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) context.getBean("userService");
    String s = userService.sayHello("张三");
    System.out.println(s);
    }
    }
  3. 执行结果
    image-20210402132035078

Spring的属性注入-注解方式

  • 使用@Autowired进行自动注入
  • @Autowired默认按照类型进行注入
    • 如果存在两个相同Bean类型,则按照名称注入
  • @Autowired注入时可以针对成员变量或者set方法
  • 通过@Autowired的required属性,设置一定要找到匹配的Bean
  • 使用@Qualifier指定注入Bean的名称
  • Spring提供对JSR-250中定义@Resource标准注解的支持
    • 使用@Resource相当于@Autowired + @Qualifier
  • @Resource和@Autowired注解功能相似

简单属性注入的注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.bean.demo;

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

/**
* Spring的Bean管理的注解方式:
* - 传统方式需要去XML配置<bean id="" class=""><bean/>
*
* @author jinglv
* @date 2021/01/22
*/
@Service("userService")
public class UserService {
/**
* 简单属性的注入
*/
@Value("米饭")
private String something;

public void eat() {
System.out.println("eat:" + something);
}

测试代码

1
2
3
4
5
6
@Test
void testEat() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.eat();
}

执行结果
image-20210402132124285

Spring的其他注解

Bean的生命周期

Spring初始化bean或销毁bean时,有时需要做一些处理工作,因此spring可以在创建和销毁bean的时候调用bean的两个生命周期的方法

1
<bean id="xxx" calss="xxxx.xxxx.xxx" init-method="init" destroy-method="destroy"/>
  • 当bean被载入到容器的时候调用init,注解方式:**@PostConstruct** 初始化
  • 当bean从容器中删除的时候调用destroy(scope=singleton有效,多例时不知道需要销毁哪个则无效),注解方式:**@PreDestroy** 销毁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.example.bean.demo;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
* Bean的生命周期
*
* @author jinglv
* @date 2021/01/25
*/
@Component("beanLifecycle")
public class BeanLifecycle {

/**
* 初始化
*/
@PostConstruct
public void init() {
System.out.println("initBean...");
}

public void say() {
System.out.println("hello...");
}

/**
* 销毁
*/
@PreDestroy
public void destroy() {
System.out.println("destroyBean...");
}
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.example.bean.demo;

import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author jinglv
* @date 2021/01/25
*/
class BeanLifecycleTest {

@Test
void say() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanLifecycle beanLifecycle = (BeanLifecycle) context.getBean("beanLifecycle");
beanLifecycle.say();
// 工厂关闭
context.close();
}
}

执行结果
image-20210402132156738

Bean的作用范围

  • 使用注解配置的Bean和<bean>配置的一样,默认作用范围都是singleton
  • @Scope注解用于指定Bean的作用范围

单例

默认是单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.bean.demo;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
* Bean的作用范围
*
* @author jinglv
* @date 2021/01/25
*/
@Component("beanScope")
@Scope
public class BeanScope {
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.bean.demo;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author jinglv
* @date 2021/01/25
*/
class BeanScopeTest {

@Test
void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanScope bean1 = (BeanScope) context.getBean("beanScope");
BeanScope bean2 = (BeanScope) context.getBean("beanScope");
System.out.println(bean1 == bean2);
}

}

执行结果
image-20210402132241184

多例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.bean.demo;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
* Bean的作用范围
*
* @author jinglv
* @date 2021/01/25
*/
@Component("beanScope")
@Scope("prototype")
public class BeanScope {
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.bean.demo;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author jinglv
* @date 2021/01/25
*/
class BeanScopeTest {

@Test
void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanScope bean1 = (BeanScope) context.getBean("beanScope");
BeanScope bean2 = (BeanScope) context.getBean("beanScope");
System.out.println(bean1 == bean2);
}

}

执行结果
image-20210402132312508

传统XML配置和注解配置混合使用

  • XML方式的优势
    • 结构清晰,易于阅读
  • 注解方式的优势
    • 开发便捷,属性注入方便
  • XML与注解的整合开发
    • 1、引入context命名空间
    • 2、在配置文件中添加context:annotation-config标签

XML配置,set方式属性注入

此演示方式是用来进行对比

创建三个类,并进行引用

ProductService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example.bean.demo.all;

/**
* @author jinglv
* @date 2021/01/28
*/
public class ProductService {

private CategoryDao categoryDao;

private ProductDao productDao;

public void setCategoryDao(CategoryDao categoryDao) {
this.categoryDao = categoryDao;
}

public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}

public void save() {
System.out.println("ProductService的save方法……");
categoryDao.save();
productDao.save();
}
}

CategoryDao.java

1
2
3
4
5
6
7
8
9
10
11
package com.example.bean.demo.all;

/**
* @author jinglv
* @date 2021/01/28
*/
public class CategoryDao {
public void save() {
System.out.println("CategoryDao的save方法执行了……");
}
}

ProductDao.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.bean.demo.all;

/**
* @author jinglv
* @date 2021/01/28
*/
public class ProductDao {

public void save() {
System.out.println("ProductDao的save方法执行了……");
}
}

XML配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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">

<!--纯XML的方式,set方法注入-->
<bean id="productService" class="com.example.bean.demo.all.ProductService">
<property name="productDao" ref="productDao"/>
<property name="categoryDao" ref="categoryDao"/>
</bean>

<bean id="productDao" class="com.example.bean.demo.all.ProductDao"/>

<bean id="categoryDao" class="com.example.bean.demo.all.CategoryDao"/>

</beans>

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.bean.demo.all;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author jinglv
* @date 2021/01/28
*/
class ProductServiceTest {

/**
* XML方式,set方式注入
*/
@Test
void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-all.xml");
ProductService productService = (ProductService) context.getBean("productService");
productService.save();
}

}

执行结果
image-20210402132346197

XML配置与注解混合使用

XML只管理类,注解的方式进行属性注入

改造ProductService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.bean.demo.all;

import javax.annotation.Resource;

/**
* @author jinglv
* @date 2021/01/28
*/
public class ProductService {

@Resource(name = "categoryDao")
private CategoryDao categoryDao;

@Resource(name = "productDao")
private ProductDao productDao;

public void save() {
System.out.println("ProductService的save方法……");
categoryDao.save();
productDao.save();
}
}

XML文件改造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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">

<!--XML只管理类,注解的方式进行属性注入-->
<context:annotation-config/>
<!--纯XML的方式,set方法注入-->
<bean id="productService" class="com.example.bean.demo.all.ProductService"/>

<bean id="productDao" class="com.example.bean.demo.all.ProductDao"/>

<bean id="categoryDao" class="com.example.bean.demo.all.CategoryDao"/>

</beans>

其他均不变,执行结果是一致的