Spring注解使用


前言

之前讲了Spring 如何创建和使用对象 , 那种初始的方法需要不停的在XML中写入 Bean对象, 如果有多个Bean对象 ,则也是比较麻烦的一种写法 , 有没有更简单的方式呢? Spring 为我们提供了一种更加简单与快捷的方式来存取Bean对象!那就是使用注解的形式 , 注解的本质就是 ,将一些代码给了第三方去完成, 你只需要调用它就行了 , 本质上还是的在XML中存储, 只不过省略你写的过程了. 交给第三方来完成了

存储Bean对象

① 配置扫描路径 -

告诉系统 扫描那个包下面有我们想要的对象, 配置同样是在XML中 ,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:content="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 https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package="com.bit.service"></content:component-scan>
</beans>

在这里插入图片描述

② 使用注解存储Bean对象

想要将对象存储在 Spring 中,有两种注解类型可以实现:

  1. 五大类注解:@Controller、@Service、@Repository. @Component、@Configuration。

这五个类注解, 使用方法是一致的 , 效果上看也是一致的 ,但是使用场景不一致 , 分别有特定的含义 , 相当于做饭里面不同的柜子 , 有的放碗 , 有的放调料 , 有的放食材 , 虽然作用都是一致的 - 存储数据 , 但是使用场景不同 ,

@Controller(控制器存储)

使用@Controller 存储 bean 的代码

@Controller
public class AATEST {
    public String f(){
        return "AATEST";
    }
}

测试代码

public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        AATEST aatest = (AATEST) context.getBean("AATEST");
        System.out.println(aatest.f());

    }

结果图
在这里插入图片描述
其他注解的使用方法与@ Controller 一致, 效果也一样, 这里就不一一演示了 .

这里讲一下Spring的调用流程 及 注解的含义

@Controller(控制器):表示的是交互层: 校验参数的合法性;
@Servie:服务层 : 业务组装;
@Repository:持久层 : 实际业务处理;
@Configuration : 配置层 (针对当前的项目做一些设置)
@Component:工具类(基础的工具)
在这里插入图片描述
有人会说了 ,不是5大类注解吗 ,怎么四个 还有个@Component 干嘛去了 ,
答案就是 : @Component :标准一个普通的spring Bean类 ,不代表特殊含义 ,但是@Component可以代替@Repository、@Service、@Controller,因为这三个注解是被@Component标注的 ,算@Component的子类

注意: 即使是用了Content添加了包路径,也是可以使用bean来注入的

getBean里面的命名规则

默认规则 : ID 等于该类的首字母小写的类名 ( 这是因为 , 咱们的类名一般都是大驼峰的命名格式)
特殊规则 : 当第一与第二的字母是大写的时候,ID等于该类的类名
不过也可以在注解里面加上(value属性值),获取的时候,获取属性值就可以了

使用⽅法注解:@Bean

类注解是添加在类上的 ,方法注解是添加在方法上的 , 理论上,如果你把一个类中的所有方法都添加上方法注解 , 那么你的效果跟类注解一模一样 ,
而且,Bean是将返回对象存放到loc容器中, 所有使用Bean必须返回对象
还有一个不方便的地方在于 , 就算你给方法添加注解, 你的类上还必须要有五大类注解之一, 要不然根本获取不到!

说了这么多是不是认为方法注解一无是处, nonono ,如果真的一无是处, 为什么不把它删除了 ,它还是有点用的, 它的作用在于可以通过设置 name 属性给 Bean 对象进⾏重命名操作,然后获取的时候使用name属性就可以了

问使用方法注解Bean,那么这个类其他方法也会存放到loc容器吗?

答: 因为加了5大类注解, 所以整个类都会加入到loc容器的

@Component
public class Users {
	 @Bean
	 public User user1() {
		 User user = new User();
		 user.setId(1);
		 user.setName("Java");
		 return user;
	 }
}

注意:
在使用@Bean注解时 , 获取Bean时, 默认情况下, 如果你没有给Bean起名字, 那么Bean的默认命名 等于 方法名

获取Bean对象

一般使用了 注解的方式来存放 Bean对象 , 那么有三种方式来获取 它, 当然不是上述的getBean()方法 , 你想,既然存放Bean可以优化, 那为啥获取Bean不能优化呢? 下面依次介绍这三种方法- 这里说一下, 这三种方法就是我们第一节提到的,依赖注入DI的实现

重命名Bean对象

默认规则是方法名

 @Bean
    public User get(){
        User user =new User();
//        user.getId();
//        user.getName();
        return user;
    }

第一种方式 : @Bean(“”);直接在Bean中写入

@Bean("aaa")
    public User get(){
        User user =new User();
//        user.getId();
//        user.getName();
        return user;
    }

第二种方式 : @Bean(name = " ") 写上name然后写入更改值

@Bean(name ="aaa")
    public User get(){
        User user =new User();
//        user.getId();
//        user.getName();
        return user;
    }

第三种方式 : @Bean(value = " ")写入value值然后写入别名

@Bean(value ="aaa")
    public User get(){
        User user =new User();
//        user.getId();
//        user.getName();
        return user;
    }

重命名扩展 :@Bean(value = {" 别名1", “别名2”) Bean支持多命名方式

@Bean(value ={"aaa","bbb"})
    public User get(){
        User user =new User();
//        user.getId();
//        user.getName();
        return user;
    }

注意 : 当Bean重命名时候, 默认命名规则就失效了

注意: 5大类注解是不能使用多命名的方式的

当多个方法使用同一个Bean注解的名字的话会报错吗?

答:不会报错, Spring有一个默认类的执行顺序, IDEA执行的时候,只会执行权重最高的
这个默认类的执行顺序,可以通过@Order(权值)来设置, 数字越大,权重越大
注: 加载类的时候, 是默认从上往下加载代码的, 如果之前代码先加载过了, 那么接下来遇到相同的Bean注解也不会重复加载.

注意: 使用Bean的时候,不能重载 , 不能重载的根本原因在于:使用@Bean注解的时候,无法传递参数,也就是说,在使用@Bean注解的时候,只能构造无参的方法

@Bean注解的总结

1: Bean注解是可以通过普通方式来获取的,类似于这样

ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        Articles articles = context.getBean("articles",Articles.class);
        articles.sayHi();

2: 普通方式获取@Bean注解,也就是getBean的内容必须是加了Bean方法的类
3:这种方式是依赖查找, 不是依赖注入, 依赖查找严格要求名称格式,
4: 当你发现失败的时候,
①应该先检查Spring.xml配置文件, 查看路径是否正确
②检查要获取的类,注解是否正确
③找到使用的类,查看名称时候填写正确

1. 属性注⼊

注: 使用@Autowired不能用main方法 , 用main方法得到属性的时候只能使用依赖查找,不能使用依赖注入(因为static类加载的时候在注入之前)*
属于依赖注入

属性注入 属于是: 骂的多, 用的多的方法了! , 为啥如此矛盾, 因为属性注入简单, 骂是因为它简单,出错概率高 , 用也是因为它简单好写!

属性注⼊是使⽤ @Autowired 实现的,将 Service 类注⼊到 Controller 类中。
代码如下

@Service
public class StuSTest {
    public User getUser(Integer id , String name){
        User user = new User();
        user.Id = id;
        user.name = name;
        return user;
    }
}
@Controller
public class StudentTest {
    @Autowired
    public StuSTest studentTest;
    public User getUser(Integer id ,String  name){
        return studentTest.getUser(id,name);
    }

}

通过 给想要的使用 的类 ,上面加上 @Autowired就可以直接使用该类的对象, 快不快! 方便不方便!
这里有个前提 : 属性注入不适用于局部变量!
注意: 使用依赖注入的时候, 先通过getType获取类型来查找,如果能够获取到,并且只有唯一的一个, 那么就会直接拿到,但是如果根据类型找到了多个,这时候才会根据名称来对应
获取多个,比如一个类注解,一个@Bean注解返回对象与类注解的一致,那么这不就是俩个了

举例:
使用@Bean注入俩个User对象

package com.java.demo.model;

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

@Component
public class Users {

    @Bean("user1")
    public User user1(){
        User user = new User();
        user.setName("张三");
        return user;
    }

    @Bean("user2")
    public User user2(){
        User user = new User();
        user.setName("李四");
        return user;
    }

}

USer对象的本体

package com.java.demo.model;

public class User {
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

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

使用@AutoWried来获取

package com.java.demo.service;

import com.java.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService2 {

    // 属性注入
    @Autowired
    
    private User user;

    public void sayHi(){
        System.out.println(user.toString());
    }

}

这个结果会报错,因为找到了俩个User对象
在这里插入图片描述
解决方案
在@Autowired注解下面加上 @Qualifier(“user2”)注解,里面是具体的方法名,这样就不会找错了

面试题 - 同类型的Bean注入多个容器,如果解决

解决方案 : 1 将获取的 对象名与方法对应上来,例如User改成User2,这样就获取的是User2的方法,我们上面说过, 但类型唯一的时候是无所谓名字的, 但是当类型不唯一的时候,就是根据名称来获取结果的

 @Autowired
    private User user2;

解决方案2 : 使用 @Qualifier(“user2”)设置名称
解决方案3 : 使用Resource 设置名称

属性注入的优缺点

缺点 :

①功能性问题 : 不能注入final(不可变对象)

被final修饰的方法, 只能直接赋值 / 或者在构造方法中赋值

②通用性问题 : 只适用于Loc容器

因为依赖@Autowried ,而@Autowried是Spring独有的,所以太过依赖于loc容器,而Set注入虽然也依赖loc容器,但是它还能作为普通方法被调用, 至于构造方法不依赖于loc容器,所以说它的通用性更好

③设计原则问题 : 更容易违背单一设计原则

更容易!

优点 :

使用简单

2. 构造⽅法注⼊ (官方推荐)

如题就是在构造方法上面加上@Autowired , 如果只有⼀个构造⽅法,那么 @Autowired 注解可以省略

@Controller
public class UserController2 {
	 // 注⼊⽅法2:构造⽅法注⼊
	 private UserService userService;
 
	@Autowired
	 public UserController2(UserService userService) {
		 this.userService = userService;
	 }
		public User getUser(Integer id) {
		 return userService.getUser(id);
	 }
}
构造方法注入的优缺点

缺点 :

①没有属性注入的方式实现简单

优点:

①可以注入一个不可变的对象

②注入的对象不会被修改

③注入对象会被完全初始化

④通用性更好
⑤当构造方法只有一个的时候, @Autowired可以省略

3. Setter 注⼊

如题, Set注入就是在在设置 set ⽅法的时候需要加上 @Autowired 注
解,如下代码所示:

@Controller
public class UserController3 {
	 // 注⼊⽅法3:Setter注⼊
	 private UserService userService;
	 @Autowired
	 public void setUserService(UserService userService) {
		 this.userService = userService;
	 }
	 public User getUser(Integer id) {
		 return userService.getUser(id);
	 }
}
ser注入的优缺点

缺点 :

①:不能注入不可变的对象

②:注入的对象是可以被修改的

优点 : 更加符合单一设计原则

获取Bean对象的注意事项

① 方法要搭配 5大类注解 去使用

② Bean 注解可以设置 name 属性

③ Bean 默认使用是方法名 , 设置了 name属性 就必须 使用 name的 名字

④使用BeanFactory (Spring创建与使用讲过)不能使用Bean注解

依赖注入与new 一个对象有什么区别

spring依赖注入,是指对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。 new一个对象的时候,初始化顺序是: 父类静态块,子类静态块,父类属性(先系统默认值,后直接你赋予的值) ,父类构造器,子类属性,子类构造器。
总结: 来做饭来举例: 加入一个菜品有多种做法 , 且所需要的材料不同, 依赖注入, 是动态的 ,是一开始不确定的,是到点做那个去买那个材料 ,而new一个对象是固定的,是需要将材料全部准备好才能在做的时候找到材料.懂了吧?所以说依赖注入,降低了耦合度!

讲了这么多注入, 下面说一个另外的注入关键字@Resource

在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊,如下代码所示:

@Controller
public class UserController {
 // 注⼊
	 @Resource
	 private UserService userService;
	 public User getUser(Integer id) {
		 return userService.getUser(id);
	 }
}

依赖注入与依赖查找的区别

在这里插入图片描述

@Autowired 与 @Resource的区别

相同点 : 都可以进行依赖注入
不同点 :

① :功能支持不同 , @Autowired支持所有方式的注入 ,而@Resource不支持构造方法的注入

②:出身地不同 @Autowired 出生与Spring 框架 , 而@Resource 出生于JDK

③:支持的参数类型不同 : @Resource 支持更多的参数, 而@Autowired只支持require参数
在这里插入图片描述
④兼容性不同 : 使用@Autowired在IDEA专业版可能会误报

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值