通过注解的方式就只能以实体类的形式进行配置了,我们在要作为配置的类上添加`@Configuration`注解
- @Configuration
- public class Config {
-
- }
等价于
- "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">
-
- beans>
在xml中我们是直接在配置文件中编写Bean的一些信息,现在在配置类中,我们只需要编写一个方法,并返回我们要创建的Bean的对象即可,并在其上方添加`@Bean`注解
- @Configuration
- public class Config {
- @Bean
- public Student student() {
- return new Student();
- }
- }
还可以继续添加`@Scope`注解来指定作用域
- @Bean
- @Scope("prototype")
- public Student student() {
- return new Student();
- }
可以在对象创建时做很多额外的操作,包括一些属性值的配置,接着我们就可以在主方法中加载此配置类,并创建一个基于配置类的容器
- public static void main(String[] args) {
- //使用AnnotationConfigApplicationContext来实现注解配置
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
- Config.class
- );
- Student student = context.getBean(Student.class);
- System.out.println(student);
- }
Bean的默认名称实际上就是首字母小写的方法名称,我们也可以手动指定
- @Bean("zzp")
- public Student student() {
- return new Student();
- }
还可以直接在类上添加`@Component`注解来将一个类进行注册(现在最常用的方式),不过要实现这样的方式,我们需要添加一个自动扫描,来告诉Spring需要在哪些包中查找我们提供`@Component`声明的Bean。
只需要在配置类上添加一个`@ComponentScan`注解即可,如果要添加多个包进行扫描,可以使用`@ComponentScans`来批量添加。
- @ComponentScan("edu.cafus.bean")
- @Configuration
- public class Config {
- }
在Student类的上面添加`@Component`注解,来表示此类型需要作为Bean交给容器进行管理:
同样的,在类上也可以直接添加`@Scope`来限定作用域
- @Component
- @Scope("prototype")
- public class Student {
- private String num;
- private int grade;
- }
与`@Component`同样效果的还有`@Controller`、`@Service`和`@Repository`
实现自动注入
先将Person类也注册为Bean,在需要注入的位置,添加一个`@Resource`注解来实现自动装配
- @Component
- public class Student {
- private String num;
- private int grade;
- @Resource
- private Person person;
- }
这样的好处是,我们完全不需要创建任何的set方法,只需要添加这样的一个注解就可以了,Spring会跟之前配置文件的自动注入一样,在整个容器中进行查找,并将对应的Bean实例对象注入到此属性中,当然,如果还是需要通过set方法来注入,可以将注解添加到方法上
- @Component
- public class Student {
- private String num;
- private int grade;
- private Person person;
-
- @Resource
- public void setPerson(Person person) {
- this.person = person;
- }
- }
除了使用`@Resource`以外,我们还可以使用`@Autowired`(IDEA不推荐将其使用在字段上,会出现黄标,但是可以放在方法或是构造方法上),它们的效果是一样的,但是它们存在区别
* @Resource默认**ByName**如果找不到则**ByType**,可以添加到set方法、字段上。
* @Autowired默认是**byType**,可以添加在构造方法、set方法、字段、方法参数上。
@Autowired`可以配合`@Qualifier`使用,来指定一个名称的Bean进行注入
- @Autowired
- @Qualifier("sxc")
- public void setCard(Card card) {
- System.out.println("通过方法");
- this.card = card;
- }
如果Bean是在配置文件中进行定义的,我们还可以在方法的参数中使用`@Autowired`来进行自动注入
- @Configuration
- public class MainConfiguration {
-
- @Bean
- public Student student(@Autowired Card card){
- Student student = new Student();
- student.setCard(card);
- return student;
- }
- }
通过`@PostConstruct`注解来添加构造后执行的方法,它等价于`init-method`
- @PostConstruct
- public void init(){
- System.out.println("我是初始化方法!1");
- num = "2";
- }
执行顺序:Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct
销毁方法可以使用`@PreDestroy`注解
现有两种通过注解进行Bean声明的方式
* 如果要注册为Bean的类是由其他框架提供,我们无法修改其源代码,那么我们就使用第一种方式进行配置。
* 如果要注册为Bean的类是我们自己编写的,我们就可以直接在类上添加注解,并在配置中添加扫描。
首先我们需要在主类添加`@EnableAspectJAutoProxy`注解,开启AOP注解支持
- @EnableAspectJAutoProxy
- @ComponentScans({
- @ComponentScan("edu.cafus.aop"),
- @ComponentScan("edu.cafus.bean")
- })
- @Configuration
- public class Config {
- }
接着我们只需在定义AOP增强操作的类上添加`@Aspect`注解和`@Component`将其注册为Bean即可,就像我们之前在配置文件中也要将其注册为Bean
- @Aspect
- @Component
- public class AopTest {
- }
直接在里面编写方法,并将此方法添加到一个切点中,比如我们希望在Student的test方法执行之前执行我们的方法
- public int test(String str){
- System.out.println("我被调用了:"+str);
- return str.length();
- }
只需要添加`@Before`注解即可
- @Before("execution(* com.test.bean.Student.test(..))")
- public void before(){
- System.out.println("我是之前执行的内容!");
- }
同样的,我们可以为其添加`JoinPoint`参数来获取切入点信息
- @Before("execution(* com.test.bean.Student.test(..))")
- public void before(JoinPoint point){
- System.out.println("参数列表:"+ Arrays.toString(point.getArgs()));
- System.out.println("我是之前执行的内容!");
- }
使用`@AfterReturning`注解来指定方法返回后的操作
- @AfterReturning(value = "execution(* com.test.bean.Student.test(..))", returning = "returnVal")
- public void after(Object returnVal){
- System.out.println("方法已返回,结果为:"+returnVal);
- }
还可以指定returning属性,并将其作为方法某个参数的实参
环绕也可以直接通过注解声明
- @Around("execution(* com.test.bean.Student.test(..))")
- public Object around(ProceedingJoinPoint point) throws Throwable {
- System.out.println("方法执行之前!");
- Object val = point.proceed();
- System.out.println("方法执行之后!");
- return val;
- }
配置文件可能不止一个,我们有可能会根据模块划分,定义多个配置文件,这个时候,可能会出现很多个配置类,如果我们需要`@Import`注解来快速将某个类加入到容器中
创建一个新的配置文件
- public class Test2Configuration {
- }
- @EnableAspectJAutoProxy
- @Configuration
- @ComponentScan("com.test")
- @Import(Test2Configuration.class)
- public class TestConfiguration {
-
- @Resource
- Connection connection;
-
- @PostConstruct
- public void init(){
- System.out.println(connection);
- }
- }
注意另一个配置类并没有添加任何注解,实际上,相当于导入的类被强制注册为了一个Bean
现在一共了解了三种注册为Bean的方式,利用这种特性,还可以将其他的类型也强制注册为Bean
- @EnableAspectJAutoProxy
- @Configuration
- @ComponentScan("com.test")
- @Import({Test2Configuration.class, Date.class})
- public class TestConfiguration {
-
- @Resource
- Connection connection;
- @Resource
- Date date;
-
- @PostConstruct
- public void init(){
- System.out.println(date+" -> "+connection);
- }
- }
日期直接作为一个Bean放入到IoC容器中了,并且时间永远都是被new的那个时间,也就是同一个对象(因为默认是单例模式)
通过`@Import`方式最主要为了实现的目标并不是创建Bean,而是为了方便一些框架的`Registrar`进行Bean定义