0%

java之spring Ioc

IoC

  • 控制反转(IoC,Inversion of Control) 是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现 方式是依赖注入,比如之前文章调用

  • 依赖:classA 类中含有 classB 的实例,在 classA 中调用 classB 的方法完 成功能,即 classA 对 classB 有依赖。

  • Ioc 的实现:依赖注入:DI(Dependency Injection),程序代码不做定位查询,这些 工作由容器自行完成。

  • idea新建一个maven-quickstart项目

  • pom.xml中加入依赖文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.16.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.16.RELEASE</version>
</dependency>
</dependencies>
  • service层代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package xyz.shi.service;
import xyz.shi.entity.User;
import java.util.ArrayList;
import java.util.List;

public class UserService {
public List<User> getUserList(){
ArrayList<User> users = new ArrayList<>();
User user1 = new User(1, "test1", "123456");
User user2 = new User(2, "test2", "123456");
User user3 = new User(3, "test3", "123456");
users.add(user1);
users.add(user2);
users.add(user3);
return users;
}
}

  • resources/application.xml
1
2
3
4
5
6
7
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="xyz.shi.service.UserService"></bean>
</beans>
1
2
3
4
<!--单例,默认是单例,可以不写--> 
<bean id="mailService" name="mailService2" class="com.mszlu.service.MailService" scope="singleton"/>
<!--非单例,每次获取都是一个新的实例,不常用-->
<bean id="mailService" name="mailService2" class="com.mszlu.service.MailService" scope="prototype"/>
  • 测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import xyz.shi.entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import xyz.shi.service.UserService;

public class userTest {
public static void main(String[] arg) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
// UserService userService =(UserService) context.getBean("userService");
UserService userService1 = context.getBean(UserService.class);
for (User user : userService1.getUserList()) {
System.out.println(user.getName());
}
}
}

ioc注解

  • 使用XML方式管理Bean以及Bean的依赖,非常直观,但是配置相对繁琐一些,尤其是当Bean多了之后,有没有更简便的方式呢?
  • Annotation配置使用注解的方式,可以极大的简化配置
1
2
3
4
5
6
7
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="xyz.shi.service" />
</beans>
  • 件扫描的作用: 让Spring知道该去哪个包中扫描注解, 以及扫描什么样的注解, 其中用到的标签就是<context:component-scan>, 其属性base-package指定扫描哪个包下的类, 多个包可以用逗号隔开, 比如:
1
<context:component-scan base-package="com.yjzzjy4.learning.beans, com.yjzzjy4.learning.test"/>
  • 关于扫描什么样的注解, 可以使用过滤器定义规则
1
2
3
<context:component-scan base-package="com.yjzzjy4.learning" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>

或者示例二:

1
2
3
<context:component-scan base-package="com.yjzzjy4.learning">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
  • 其中<context:component-scan>的use-default-filters属性指定是否使用Spring默认的过滤器, 是一个布尔属性, 默认为true, 即扫描所有注解. 当设为false的时候, 则需要自己配置扫描规则, 通常用<context:include-filter>来包含要扫描的注解类型(示例一), 如果使用默认过滤器, 则通常会使用<context:exclude-filter>注解来排除掉不想要扫描的注解类型(示例二), 其中:
    • org.springframework.stereotype.Component: 即@Component注解;
    • org.springframework.stereotype.Service:即@Service注解;
  • 而type属性值设为annotation即说明过滤器的作用对象是注解.

创建对象

Spring提供了以下四个注解用于创建对象:

  • @Component: 建议用于普通Bean;
  • @Controller: 建议用在Web层的Controller;
  • @Repository: 建议用在DAO层的仓储Bean;
  • @Service: 建议用在Service层的Bean.
  • 实际上这四个注解都是实现相同的功能, Spring将它们区分开来仅仅是为了应用开发的逻辑清晰, 并没有硬性规定这几个注解的使用场合, 这些注解都有一个属性: value, 用于指定Bean的id, 即:
1
2
@Component(value = "employee")
值得注意的是, 默认情况下若不给value设置值, 则value自动取类名首字母小写为值
  • 等价于:
1
<bean id="employee" .../>

练习

resources-application.xml

1
2
3
4
5
6
7
8
9
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描整个目标文件夹 -->
<context:component-scan base-package="xyz.shi" />
</beans>
  • controller注解
1
2
3
4
5
6
7
package xyz.shi.controller;
import org.springframework.stereotype.Controller;

@Controller
public class PersonController {
}

  • Repository 注解dao
1
2
3
4
5
package xyz.shi.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
}
  • Service 注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package xyz.shi.service;
import xyz.shi.entity.User;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public static List<User> getUserList(){
ArrayList<User> users = new ArrayList<>();
User user1 = new User(1, "test1", "123456");
User user2 = new User(2, "test2", "123456");
User user3 = new User(3, "test3", "123456");
users.add(user1);
users.add(user2);
users.add(user3);
return users;
}
}
  • Component注解实体类
1
2
3
4
5
6
7
8
9
10
package xyz.shi.entity;

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

@Component(value = "userBean")
@Scope(value = "prototype")
public User () {

}
  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class userTest {
public static void main(String[] arg) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
System.out.println(context.getBean("personController"));
System.out.println(context.getBean("userService"));
System.out.println(context.getBean("userDao"));
System.out.println(context.getBean("userBean"));
System.out.println(context.getBean("role"));
}

}
  • 结果如下
1
2
3
4
5
xyz.shi.controller.PersonController@1cab0bfb
xyz.shi.service.UserService@5e955596
xyz.shi.dao.UserDao@50de0926
xyz.shi.entity.User@2473b9ce
xyz.shi.entity.Role@60438a68

注入属性

IoC的第二个任务就是注入属性, Spring提供了三个注解用于完成此任务:

  • @Autowired: 按类型进行自动装配, 不可以有多个相同类型的Bean;
  • @Qualifier: 按名称进行装配, 要和@Autowired一起使用;
  • @Value: 注入值类型属性.
  • 还有一个注解是由Java提供的:
    • @Resource: 既可以根据类型, 也可以根据名称注入, 相当于@Autowired@Qualifier.
    • 通常建议使用Spring提供的注解, 因为在以后的Spring版本迭代中将会更可控一些.

使用@AutoWired进行自动注入

  • dao
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package xyz.shi.dao;
import org.springframework.stereotype.Repository;
import xyz.shi.entity.User;

import java.util.ArrayList;
import java.util.List;

@Repository
public class UserDao {
public List<User> getUserList(){
ArrayList<User> users = new ArrayList<>();
User user1 = new User(1, "test1", "123456");
User user2 = new User(2, "test2", "123456");
User user3 = new User(3, "test3", "123456");
users.add(user1);
users.add(user2);
users.add(user3);
return users;
}
}

  • service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package xyz.shi.service;
import org.springframework.beans.factory.annotation.Autowired;
import xyz.shi.dao.UserDao;
import xyz.shi.entity.User;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public List<User> getUserList(){
return userDao.getUserList();
}
}

Autowired 加入后,不用在实例化了

  • controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package xyz.shi.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import xyz.shi.entity.User;
import xyz.shi.service.UserService;

import java.util.List;

@Controller
public class UserController {
@Autowired
private UserService userService;
public List<User> getUserList() {
return userService.getUserList();
}
}

  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import xyz.shi.controller.UserController;
import xyz.shi.entity.User;

import java.util.List;

public class userTest {
public static void main(String[] arg) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
UserController userController = context.getBean("userController", UserController.class);
List<User> users = userController.getUserList();
for(User user: users) {
System.out.println(user.getName());
}
}
}

@Qualifier注解

  • 修改UserControll.java加上@Qualifer注解,指定id为userService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package xyz.shi.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import xyz.shi.entity.User;
import xyz.shi.service.UserService;

import java.util.List;

@Controller
public class UserController {
@Autowired
@Qualifier("userService")
private UserService userService111;
public List<User> getUserList() {
return userService111.getUserList();
}
}

这样运行测试代码是没有问题,如果是@Qualifier(“userService1”),就会报错,因为找不到对应的name

  • AutoWired可以进行定义在方法上
1
2
3
4
@Autowired
public void test(PersonDao personDao){
System.out.println("personDao:"+personDao);
}
  • @Qualifier注解也可以作用在属性上,用来被当作id去匹配容器中的对象,如果没有 此注解,那么直接按照类型进行匹配
1
2
3
public void test1(@Qualifier("personServiceSon") PersonService personService){
personService.getPerson();
}