1 声明Bean的注解
负责声明Bean的注解,常见的包括四个:
- @Component
- @Controller
- @Service
- @Repository
@Controller、@Service、@Repository这三个注解都是@Component注解的别名。
也就是说:这四个注解的功能都一样。用哪个都可以。
只是为了增强程序的可读性,建议:
- 控制器类上使用:Controller
- service类上使用:Service
- dao类上使用:Repository
他们都是只有一个value属性。value属性用来指定bean的id,也就是bean的名字
2 Spring注解的使用
如何使用以上的注解呢?
-
第一步:加入aop的依赖
当加入spring-context依赖之后,会关联加入aop的依赖。
-
第二步:在配置文件中添加context命名空间
<?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"> </beans>
-
第三步:在配置文件中指定扫描的包
<!--给spring框架指定要扫描的包--> <context:component-scan base-package="com.powernode.spring6.bean"/>
-
第四步:在Bean类上使用注解
package com.powernode.spring6.bean; import org.springframework.stereotype.Component; @Component("userBean") public class User { }
以上注解就相当于以下这个配置信息:
<bean id="userBean" class="com.powernode.spring6.bean.User"/>
测试
@Test public void testBeanComponent(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); User user = applicationContext.getBean("userBean", User.class); System.out.println(user); }
注解的属性名是value,那么value是可以省略的。
如果把value属性全部省略,Bean有默认的名称:Bean类名首字母小写。
如果是多个包有两种解决方案:
第一种:在配置文件中指定多个包,用逗号隔开。
第二种:指定多个包的共同父包。
<!--多个包,使用,隔开-->
<context:component-scan base-package="com.powernode.spring6.bean, com.powernode.spring6.dao"/>
<!--多个包,也可以指定这多个包共同的父包,牺牲一部分效率-->
<context:component-scan base-package="com.powernode.spring6"/>
3 选择性实例化Bean
use-default-filters=“true” 表示:使用spring默认的规则,只要有Component、Controller、Service、Repository中的任意一个注解标注,则进行实例化。
use-default-filters=“false” 表示:不再spring默认实例化规则,即使有Component、Controller、Service、Repository这些注解标注,也不再实例化。
<!--
第一种解决方案:
use-default-filters="false"
如果这个属性是false,表示com.powernode.spring6.bean包下所有的带有声明Bean的注解全部失效。@Component @Controller @Service @Repository全部失效。
-->
<context:component-scan base-package="com.powernode.spring6.bean" use-default-filters="false">
<!--包含-->
<!--只有@Repository @Service被包含进来,生效-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<!--
第二种解决方案:
use-default-filters="true"
如果这个属性的值是true,表示com.powernode.spring6.bean下的所有的带有声明Bean的注解全部生效。
use-default-filters="true" 默认值就是true,不用写。
-->
<context:component-scan base-package="com.powernode.spring6.bean">
<!--排除掉-->
<!--@Controller失效-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
4 负责注入的注解
给Bean属性赋值需要用到这些注解:
-
@Value
-
@Autowired
-
@Qualifier
-
@Resource
1 @Value
当属性的类型是简单类型时,可以使用@Value注解进行注入。
使用@Value注解注入的话,可以用在属性上,并且可以不提供setter方法
// 使用@Value注解注入的话,可以用在属性上,并且可以不提供setter方法 @Value("com.mysql.cj.jdbc.Driver") private String driver; @Value("jdbc:mysql://localhost:3306/spring6") private String url; @Value("root") private String username; @Value("root") private String password;
@Value注解也可以使用在setter方法上
private String driver; private String url; private String username; private String password; // @Value注解也可以使用在setter方法上 @Value("com.mysql.cj.jdbc.Driver") public void setDriver(String driver) { this.driver = driver; } @Value("jdbc:mysql://localhost:3306/spring6") public void setUrl(String url) { this.url = url; } @Value("root") public void setUsername(String username) { this.username = username; } @Value("root") public void setPassword(String password) { this.password = password; }
@Value注解也可以用在构造方法的形参上
private String driver; private String url; private String username; private String password; // @Value注解也可以用在构造方法的形参上 public MyDataSource(@Value("com.mysql.cj.jdbc.Driver") String driver, @Value("jdbc:mysql://localhost:3306/spring6") String url, @Value("root") String username,@Value("root") String password) { this.driver = driver; this.url = url; this.username = username; this.password = password; }
2 @Autowired与@Qualifier
@Autowired注解可以用来注入非简单类型。被翻译为:自动连线的,或者自动装配。
单独使用@Autowired注解,默认根据类型装配。【默认是byType】OrderDao接口
package org.powernode.dao; public interface OrderDao { void insert(); }
OrderDao接口的实现类
package org.powernode.dao.impl; import org.powernode.dao.OrderDao; import org.springframework.stereotype.Repository; @Repository("orderDaoImplForMySQL") public class OrderDaoImplForMySQL implements OrderDao { @Override public void insert() { System.out.println("MySQL数据库正在保存订单信息...."); } }
OrderService
package org.powernode.service; import org.powernode.dao.OrderDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("orderService") public class OrderService { // @Autowired注解使用的时候,不需要指定任何属性,直接使用 // 根据类型byType进行自动装配 @Autowired private OrderDao orderDao; public void generate(){ orderDao.insert(); } }
配置包扫描
<?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="org.powernode"/> </beans>
测试程序
@Test public void testAutowired(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowired.xml"); OrderService orderService = applicationContext.getBean("orderService", OrderService.class); orderService.generate(); }
@Autowired注解默认是byType进行注入的,也就是说根据类型注入的,如果以上程序中,UserDao接口如果有多个实现类,会出现错误,错误信息中说:不能装配,UserDao这个Bean的数量大于1.
怎么解决这个问题?byName,根据名称进行装配了。
@Autowired注解和@Qualifier注解联合起来才可以根据名称进行装配,在@Qualifier注解中指定Bean名称。package org.powernode.service; import org.powernode.dao.OrderDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Service("orderService") public class OrderService { // @Autowired和@Qualifier联合使用,可以根据名字自动装配 @Autowired @Qualifier("orderDaoImplForMySQL") private OrderDao orderDao; public void generate(){ orderDao.insert(); } }
@Autowired注解可以出现的位置:属性上、构造方法上、构造方法的参数上、setter方法上。
当带参数的构造方法只有一个,并且构造方法上的参数和属性能够对应上,@Autowired注解可以省略。
3 @Resource
@Resource注解也可以完成非简单类型注入。那它和@Autowired注解有什么区别?
- @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
- @Autowired注解是Spring框架自己的。
- @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
- @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。
- @Resource注解用在属性上、setter方法上。
- @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。
引入依赖Spring6+版本使用这个依赖
<dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>2.1.1</version> </dependency>
StudentDao接口
package cn.powernode.dao; public interface StudentDao { void deleteById(); }
StudentDao接口的实现类
package cn.powernode.dao.impl; import cn.powernode.dao.StudentDao; import org.springframework.stereotype.Repository; @Repository("studentDaoImplForMySQL") public class StudentDaoImplForMySQL implements StudentDao { @Override public void deleteById() { System.out.println("MySQL正在删除学生信息..."); } }
StudentService
package cn.powernode.service; import cn.powernode.dao.StudentDao; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @Service("studentService") public class StudentService { @Resource(name = "studentDaoImplForMySQL") private StudentDao studentDao; /*@Resource(name = "studentDaoImplForMySQL") public void setStudentDao(StudentDao studentDao) { this.studentDao = studentDao; }*/ public void deleteStudent(){ studentDao.deleteById(); } }
配置包扫描
<?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="cn.powernode"/> </beans>
测试程序:
@Test public void testResource(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-resource.xml"); StudentService studentService = applicationContext.getBean("studentService", StudentService.class); studentService.deleteStudent(); }
@Resource注解:默认byName注入,没有指定name时把属性名当做name,根据name找不到时,才会byType注入。byType注入时,某种类型的Bean只能有一个。
5 全注解式开发
写一个配置类来代替配置文件。
package cn.powernode;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 编写一个类代替Spring框架的配置文件
*/
@Configuration
// 组件扫描
@ComponentScan({"cn.powernode.dao", "cn.powernode.service"})
public class Spring6Config {
}
编写测试程序:不再new ClassPathXmlApplicationContext()对象了。
new AnnotationConfigApplicationContext()对象
@Test
public void testNoXML(){
ApplicationContext applicationContext= new AnnotationConfigApplicationContext(Spring6Config.class);
StudentService studentService = applicationContext.getBean("studentService", StudentService.class);
studentService.deleteStudent();
}