什么是spring注解开发?
就是不再使用Spring的bean.xml文件,纯使用注解的方式开发;
要使用纯注解开发,就需要有一个配置类,配置类==配置文件
spring版本:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.5.RELEASE</version> </dependency>
@Configuration:一旦在某个类上标注了此注解,说明此类就是一个配置类
注解的定义如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
@Bean:给容器中注册一个bean;类型为返回值的类型,id默认使用方法名作为id
注解的定义如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
/** @deprecated */
@Deprecated
Autowire autowire() default Autowire.NO;
boolean autowireCandidate() default true;
String initMethod() default "";
String destroyMethod() default "(inferred)";
}
定义一个名为Person的类,如下
package com.yuan.bean;
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
传统的方式实现注册一个bean的方式:
1.编写spring的核心配置文件,如bean.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: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 ">
<!--包扫描xml配置:只要标注了@Controller、@Service、@Repository、@Component等注解,它们会自动的加载到IOC容器中-->
<!--<context:component-scan base-package="com.yuan"></context:component-scan>-->
<!--使用set方式赋值-->
<bean id="person" class="com.yuan.bean.Person">
<property name="age" value="22" />
<property name="name" value="jinshengyuan"/>
</bean>
</beans>
package com.yuan;
import com.yuan.bean.Person;
import com.yuan.config.MainConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
public static void main(String[] args) {
//xml配置的方式
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
}
}
执行结果:Person{name='jinshengyuan', age=22}
使用注解驱动开发方式注册一个bean
package com.yuan.config;
import com.yuan.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//配置类 == 配置文件
@Configuration //告诉spring这是一个配置类
public class MainConfig {
/**
* @Bean注解: 给容器中注册一个bean;类型为返回值的类型,id默认使用方法名作为id
* 如果要自己指定id,则需要加上name属性,如:@bean(value="person"),value可省略写成@Bean("person")
* @return
*/
@Bean(name = "person")
public Person person01(){
return new Person("张三",20);
}
}
package com.yuan;
import com.yuan.bean.Person;
import com.yuan.config.MainConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
public static void main(String[] args) {
//xml配置的方式
/*ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);*/
//使用注解的方式为IOC容器注册一个组件
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
//根据类型获取bean的名称
String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
for (int i=0;i<beanNamesForType.length;i++){
System.out.println(beanNamesForType[i]);
}
}
}
@ComponentScan:只要标注了@Controller、@Service、@Repository、@Component等注解,它们会通过@ComponentScan自动的加载到IOC容器中
@ComponentScan属性:
@ComponentScan.Filter的属性:
@ComponentScan.Filter的属性type过滤规则
FilterType.ANNOTATION:按照注解(常用)
FilterType.ASSIGNABLE_TYPE :按照给定的类型(常用)
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.CUSTOM :使用自定义规则
FilterType.REGEX :使用正则表达式指定
<context:component-scan base-package="com.yuan"></context:component-scan>
package com.yuan.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
@Configuration
@ComponentScan(value = "com.yuan",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},includeFilters = {
@ComponentScan.Filter(type =FilterType.ANNOTATION,classes = {Service.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes ={BookServices.class}
},useDefaultFilters = false) //自动扫描的包
//excludeFilters = ComponentScan.Filter[] : 指定扫描的时候按照什么规则排除哪些组件
//includeFilters = ComponentScan.Filter[] : 指定扫描的时,只需要包含哪些组件,还需配合禁用掉默认规则一起使用
//useDefaultFilters = false : 禁用自动扫描的的默认规则
//如果是Java8版本,则可以多次使用@ComponentScan注解,如果Java8之前的版本,则使用@ComponentScans注解来多次使用@ComponentScan注解
@ComponentScan(...) //java8中可以写多个@ComponentScan
@ComponentScan(...) //java8中可以写多个@ComponentScan
public class MyConfigOne {
@Bean("person")
public Person person(){
return new Person("李四",25);
}
}
package com.yuan.config;
import com.yuan.bean.Person;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
@Configuration
@ComponentScans(
value = {
@ComponentScan(value = "com.yuan", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class})
}, useDefaultFilters = false) //自动扫描的包
}
)
//excludeFilters = ComponentScan.Filter[] : 指定扫描的时候按照什么规则排除哪些组件
//includeFilters = ComponentScan.Filter[] : 指定扫描的时,只需要包含哪些组件,还需配合禁用掉默认规则一起使用
//useDefaultFilters = false : 禁用自动扫描的的默认规则
//如果是Java8版本,则可以多次使用@ComponentScan注解,如果Java8之前的版本,则使用@ComponentScans注解来多次使用@ComponentScan注解
public class MyConfigOne {
@Bean("person")
public Person person(){
return new Person("李四",25);
}
}
package com.yuan.config;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
/**
* @ComponentScan.Filter 的type属性自定义规则类(type = FilterType.CUSTOM),实现了TypeFilter接口
*/
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader the metadata reader for the target class (读取到的正在扫描的类的信息)
* @param metadataReaderFactory a factory for obtaining metadata readers (是一个工厂,可以获取其他任何类的信息)
* * for other classes (such as superclasses and interfaces)
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的信息,比它的类型式什么,实现了哪些接口等等
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类的类名
String className = classMetadata.getClassName();
System.out.println("---className---->>>>"+className);
//获取当前类的资源信息(如类的路径)
Resource resource = metadataReader.getResource();
//如果类名中包含er则匹配成功
if(className.contains("er")){
return true;
}
return false;
}
}
package com.yuan.config;
import com.yuan.bean.Person;
import org.springframework.context.annotation.*;
@Configuration
//如果Java8之前的版本,则使用@ComponentScans注解来多次使用@ComponentScan注解
@ComponentScans(
value = {
@ComponentScan(value = "com.yuan", includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}, useDefaultFilters = false) //自动扫描的包
}
)
/*
@ComponentScan.Filter过滤规则
FilterType.ANNOTATION:按照注解(常用)
FilterType.ASSIGNABLE_TYPE :按照给定的类型(常用)
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.CUSTOM :使用自定义规则
FilterType.REGEX :使用正则表达式指定
*/
public class MyConfigTwo {
@Bean(value = "person")
public Person person() {
return new Person("张三", 33);
}
}
package com.yuan.test;
import com.yuan.config.MainConfig;
import com.yuan.config.MyConfigTwo;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class IOCTest {
@Test
public void testTwo(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigTwo.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
---className---->>>>com.yuan.test.IOCTest
---className---->>>>com.yuan.MainTest
---className---->>>>com.yuan.bean.Person
---className---->>>>com.yuan.config.MainConfig
---className---->>>>com.yuan.config.MyConfigOne
---className---->>>>com.yuan.config.MyTypeFilter
---className---->>>>com.yuan.controller.BookController
---className---->>>>com.yuan.dao.BookDao
---className---->>>>com.yuan.services.BookServices
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfigTwo ----配置类自己
person ----@Bean加载的person类,由容器创建的,所有会看到
下面这三个就是由MyTypeFilter过滤规则进行过滤的类
myTypeFilter
bookController
bookServices