zl程序教程

您现在的位置是:首页 >  后端

当前栏目

吃透Spring框架(三)

Spring框架 吃透
2023-06-13 09:11:24 时间

1. Spring 相关注解

在讲注解之前我们先看一下啥是注解。

代码格式:@英文单词,例如:

作用位置:常用在类上或者方法上

用处:简化代码、完成某些功能

所以 Spring 引入注解也是为了简化我们的代码,通过使用简单的注解完成一些功能。

1.1 创建对象相关注解

我们前面在学 IOC 的时候知道如果想让 Spring 创建对象,必须要在配置文件中写 bean 标签。

<bean id="calculateService"  class="com.xxl.service.impl.CalculateServiceImpl" />
<bean id="proxyBeanPostProcessor" class="com.xxl.aop.ProxyBeanPostProcessor"/>
<bean id="testMyAspect"  class="com.xxl.aop.TestAspect" />
......

可是如果想让 Spring 管理一堆对象,我们就要写一堆 bean 标签。所以 Spring 为了简化代码,提供了一些与创建对象相关的注解。

1.1.1 @Component

作用:替换 bean 标签,用来创建对象。就是在类上面加了这个注解,就不用在配置文件上写 bean 标签了。

位置:类上面

id 属性:默认首单词首字母小写。

// id 属性:默认首单词首字母小写。
@Component("user")
public class User{

}

1.1.2 @Component 衍生注解

我们在开发程序的时候一般会将程序分层,例如分为控制层(controller),业务层(service),持久层(dao)。

但是 @Component 注解并不能区分这些类属于那些层,所以 Spring 提供了以下衍生注解:

1.@Controller:表示创建控制器对象

@Controller
public class UserController {
    
}

2.@Service:表示创建业务层对象

@Service
public class UserServiceImpl implements UserService {

}

3.@Repository:表示创建持久层对象

@Repository
public class UserDaoImpl implements UserDao {

}

这三个注解的作用和 @Component 的作用一样,都是用来创建对象。

1.1.3 @Scope

我们知道 Spring 工厂创建的对象默认都是单例的,也就是 bean 标签中 scope 属性默认是 singleton。

@Scope 注解可以用来修改创建对象的 scope 属性。

默认:也就是说你不写 @Scope 注解,默认就是 singleton,所以可以省略。

@Component
// 可以省略不写
@Scope("singleton")
public class User {
    
}

修改多例:

@Component
@Scope("prototype")
public class User {
    
}

1.1.4 生命周期相关注解

1.@PostConstruct

初始化方法注解,作用在方法上。用来替换 bean 标签的 init-method 属性。

例如:

@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
    // 初始化方法
    @PostConstruct
    public void init(){
        this.name = "王小波";
    }
}

测试:

@Test
public void testSpring() {
    // 1、获取工厂
    ApplicationContext act = new ClassPathXmlApplicationContext("/applicationContext.xml");
    // 2、通过工厂类获得对象
    User user = (User) act.getBean("user");
    System.out.println(user);
}

报错了!这是为什么?

我们先看报错内容:

No bean named 'user'

也就是说找不到这个对象。我们虽然加了 @Component 注解,但是 Spring 不知道啊,所以需要在 Spring 的配置文件中配置注解扫描

<context:component-scan base-package="com.xxl"/>

base-package: 添加注解的类所在的包位置。

配置了注解扫描,当程序启动的时候 Spring 会先扫描一下相关的注解,这些注解才会生效。

就比如你去快递驿站拿快递,你看到了自己的快递然后对快递小哥说:"这我的快递我拿走了啊。"但是人家小哥无法确认是你的啊!所以他需要用扫码枪扫一下才能出货!

我们配置注解扫描之后再次测试:

2.@PreDestory(了解即可)

销毁方法注解,作用在方法上。用来替换 bean 标签的 destory-method 属性。

1.2 注入相关注解

1.2.1 @Autowired

我们之前学 DI 的时候知道:注入就是赋值

@Autowired 主要是为自定义的类型赋值,例如 service、dao 层的各种类。

@Controller
public class UserController {

    @Autowired
    private UserService userService;
}
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
}

@Autowired 是基于类型进行注入,所注入对象的类型必须和目标变量类型相同或者是他的子类、实现类。

如果想基于名字注入,可以和 @Qualifier 注解连用:

@Autowired
@Qualifier("orderDAOImpl")
private OrderDAO orderDAO;

1.2.2 @Resource

@Resource 注解是 JAVAEE 规范中提供的注解,他和 @Autowired 注解的作用一样, 但是他是基于名字进行注入:

@Resource("orderDAOImpl")
private OrderDAO orderDAO;

在实际开发中,用 @Autowired 注解比较多一点。

1.2.3 案例

Product 类

@Component
public class Product {

    private  String productName;

    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }

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

    @PostConstruct
    public void init(){
        this.productName = "西瓜";
    }
}

User 类:

@Component
public class User {
    private String name;

    @Autowired
    private Product product;

    public String getName() {
        return name;
    }

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

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    @PostConstruct
    public void init(){
        this.name = "小明";
    }

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

测试:

@Test
public void testSpring() {
    // 1、获取工厂
    ApplicationContext act = new ClassPathXmlApplicationContext("/applicationContext.xml");
    // 2、通过工厂类获得对象
    User user = (User) act.getBean("user");
    System.out.println(user);
}

1.3 Spring 配置文件相关注解

1.3.1 @Configuration

@Configuration 注解用于替换 xml 配置文件。

@Configuration
public class SpringConfig {
    
}

意思就是说你在一个类上面加一个 @Configuration 注解,这个类就可以看成 Spring 的配置类,你就不用再写 xml 文件了。

我们之前是根据 xml 文件创建 Spring 的工厂,那怎样根据配置类创建工厂呢?

有两种方式:

方式一:根据类.class

ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

方式二:根据配置类所在的路径

ApplicationContext ctx = new AnnotationConfigApplicationContext("com.xxl");

1.3.2 @Bean

@Bean 注解也是用来创建对象的,相当于spring 配置文件中的 bean 标签。

@Configuration
public class SpringConfig {

    @Bean
    public Product getProduct(){
        return new Product();
    }
}

自定义 id 值:

@Configuration
public class SpringConfig {

    @Bean("product")
    public Product getProduct(){
        return new Product();
    }
}

不过在实际开发中我们一般会用 @Bean 注解创建一些复杂的对象,例如 Redis、MQ 等一些组件对象。

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

1.3.3 @ComponentScan

@ComponentScan 注解相当于 xml 配置文件中的注解扫描标签:

<context:component-scan base-package="com.xxl"/>

作用:用来扫描@Component 等相关注解

属性:

basePackages:注解所在的包路径

例如:

@Configuration
@ComponentScan(basePackages = "com.xxl")
public class SpringConfig {
}

2. 注解小案例

1.User 类

@Component
public class User {
    private String name;

    @Autowired
    private Product product;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Product getProduct() {
        return product;
    }
    public void setProduct(Product product) {
        this.product = product;
    }

    @PostConstruct
    public void init(){
        this.name = "渣渣辉";
    }

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

2.Product 类

@Component
public class Product {
    private  String productName;
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    @Override
    public String toString() {
        return "Product{" +
                "productName='" + productName + '\'' +
                '}';
    }
}

3.配置类:

@Configuration
@ComponentScan(basePackages = "com.xxl")
public class SpringConfig {

    @Bean
    public Product product() {
        Product product = new Product();
        product.setProductName("草莓味的番茄");
        return product;
    }
}

4.测试

@Test
public void testSpring() {
    // 1、获取工厂
    ApplicationContext act = new AnnotationConfigApplicationContext(SpringConfig.class);
    // 2、通过工厂类获得对象
    User user = (User) act.getBean("user");
    System.out.println(user);
}

-END-