spring版本更改 spring @version
转载
Spring常用注解说明
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.levi.java</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 版本变量控制 -->
<properties>
<!-- 源码编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Maven编译版本 -->
<maven.compiler.version>3.1</maven.compiler.version>
<!-- 指定一下jdk的版本 ,这里我们使用jdk 1.8 ,默认是1.6 -->
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
<!-- 构建节点. -->
<build>
<plugins>
<!-- 项目编译插件,所有子项目都必备的插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
|
基础测试类
publicclass Student {
private String name;
public Student() {
System.out.println("构造...");
}
public Student(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
publicvoid init(){
System.out.println("init...");
}
publicvoid destroy(){
System.out.println("destroy...");
}
@Override
public String toString() {
return "Student [name=" + name + "]";
}
}
|
Xml配置方式启动项目
publicclass Student {
private String name;
public Student() {
System.out.println("构造...");
}
public Student(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
publicvoid init(){
System.out.println("init...");
}
publicvoid destroy(){
System.out.println("destroy...");
}
@Override
public String toString() {
return "Student [name=" + name + "]";
}
}
|
<?xml version="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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.levi.spring.annotations.levi01beanxml.Student">
<property name="name" value="abc"></property>
</bean>
</beans>
|
/**
* 以前是使用xml配置化时,就是使用ClassPathXmlApplicationContext
*/
publicclass L01MainTest {
publicstaticvoid main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test.xml");
Student student = (Student) applicationContext.getBean("student");
System.out.println(student.getName());
}
}
|
@Configuration
/**
* @Configuration是用于定义配置类,可替换Xml配置文件,被注解的类的内部包含一个或多个被@Bean注释的方法,
* 这些方法会被AnnotaionConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,
* 并用于构建bean定义,初始化Spring容器。
*/
@Configuration
publicclass L02MainConfig {
@Bean
public Student student() {
returnnew Student();
}
@Bean
public Student getStudent() {
returnnew Student();
}
publicstaticvoid main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(L02MainConfig.class);
Student student = (Student) applicationContext.getBean("student");
// Student student2 = (Student) applicationContext.getBean("getStudent");
System.out.println(student);
// System.out.println(student2);
}
}
|
@ComponentScan
/**
* @ComponentScan:根据定义的扫描路径,把符合扫描规则的类装配到Spring容器中。
* 参数:
* value:只扫描包
* excludeFilters:指定扫描时,按照扫描规则排除哪些组件。
* includeFilters:指定扫描时,只需要包含哪些组件
* Filter.ANNOTATION:按照注解过滤
* Filter.ASPECTJ:根据Aspetj的表达式
* Filter.REGEX:按照正则表达式
* Filter.CUSTOM:自定义规则
*/
@Configuration
@ComponentScan(value = {"com.levi.spring.annotations.levi02scan"},
includeFilters = {@Filter(type=FilterType.ANNOTATION)})
publicclass ComponentScanConfig {
@Bean
public Student student() {
returnnew Student();
}
}
|
/**
*
* @authorsuzhiwei
*/
publicclass MainConfig {
publicstaticvoid main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ComponentScanConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}
|
@Scope
@Configuration
publicclass MainConfig {
/**
* @Scope:指定位于Spring容器中的实例,默认是单例。
* singleton:默认,单例。IOC容器启动时会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中获取(Map)同一个
* prototype:多实例,IOC容器启动的时候,不会去调用方法创建对象,而是每次获取的时候才会调用方法创建对象。另外,这也是为什么@Lazy对多例无效。
* request:针对Web应用,一次请求创建一个对象。
* session:同一个session创建一个实例。
*/
@Scope(value = "prototype")
// @Scope
@Bean
public Student student() {
returnnew Student();
}
publicstaticvoid main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Student student = (Student) applicationContext.getBean("student");
Student student2 = (Student) applicationContext.getBean("student");
System.out.println(student);
System.out.println(student2);
}
}
|
@Lazy
@Configuration
publicclass MainConfig {
/**
* @Lazy:懒加载价值只对单例bean起作用,对于多例bean设置懒加载没有意义,因为多实例bean本来就是在使用时才创建。
* 在没有用@Lazy注释标注时,不会启动懒加载,在容器创建的时候,就会初始化bean了。
* 非懒加载的好处在于可以提前发现错误,但是消耗资源。
*/
@Lazy
@Bean
public Student student() {
returnnew Student();
}
publicstaticvoid main(String[] args) {
/*
* 有@Lazy结果:
* IOC
* 构造对象...
*
* 无@Lazy结果:
* 构造...
* IOC
*/
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("IOC");
Student student = (Student) applicationContext.getBean("student");
System.out.println(student);
}
}
|
@Conditional
publicclass LeviConditional implements Condition {
@Override
publicboolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
System.out.println("正在使用的类:" + beanFactory.getClass());
String systemName = context.getEnvironment().getProperty("os.name");
System.out.println("系统类型:" + systemName);
System.out.println("不同系统类型做不同的事情。");
if(systemName.contains("Windows")) {
System.out.println("Windows系统允许创建");
returntrue;
}
returnfalse;
}
}
|
@Configuration
publicclass MainConfig {
/**
* @Conditional:只有的满足某些条件的情况下才会注入到IOC容器中
*/
@Conditional(value = LeviConditional.class)
@Bean
public Student student() {
returnnew Student();
}
publicstaticvoid main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Student student = (Student) applicationContext.getBean("student");
System.out.println(student);
}
}
|
往容器注册组件的方式(注解)@Bean、@Import、ImportSelector、ImportBeanDefinitionRegistrar、FactoryBean
|
|
|
|
publicclass LeviFactoryBean implements FactoryBean<Boy> {
@Override
public Boy getObject() throws Exception {
returnnew Boy();
}
@Override
public Class<?> getObjectType() {
return Boy.class;
}
@Override
publicboolean isSingleton() {
returntrue;
}
}
|
publicclass LeviImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
publicvoid registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//判断这个是否在容器内
boolean containsBeanDefinition = registry.containsBeanDefinition("com.levi.spring.annotations.levi06import.Teacher");
System.out.println("========== LeviImportBeanDefinitionRegistrar:" + containsBeanDefinition);
if (containsBeanDefinition) {
//如果在容器内,那么就把Girl类创建出来也加入到容器中
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Girl.class);
registry.registerBeanDefinition("girl", rootBeanDefinition);
}
}
}
|
publicclass LeviImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//返回全类名的bean
returnnew String[] {"com.levi.spring.annotations.levi06import.Person"};
}
}
|
@Configuration
@Import(value = {Teacher.class,LeviImportSelector.class,LeviImportBeanDefinitionRegistrar.class,LeviFactoryBean.class})
publicclass MainConfig {
/**
* 容器注册组件的方式:
* 1、@Bean:导入类或包到IOC容器中
* 2、包扫描+组件的标注注解,一般针对自己写的类,@ComponentScan、@Controller、@Service、@Repository、@Componet
* 3、@Import:导入类或包到IOC容器中,bean的id为类名,主要是@Bean比较简单
* ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
* ImportBeanDefinitionRegistrar:实现ImportBeanDefinitionRegistrar接口即可。
* 4、使用Spring提供的FactoryBean(工厂bean)进行注册
* BeanFactory是直接从IOC中获取实例化后的实例
* FactoryBean是可以自定义Bean构建时这个过程加入自定义的内容
*/
@Bean
public Student student() {
returnnew Student();
}
@Bean("studentT")
public Student studentT() {
returnnew Student();
}
publicstaticvoid main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Student student = (Student) applicationContext.getBean("student");
System.out.println(student);
Student student2 = (Student) applicationContext.getBean("studentT");
System.out.println(student2);
//打印所有定义的类
for (String name : applicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
|
Bean初始化与销毁方式(@Bean、InittializingBean & DisposableBean、JSR250注解@PreDestroy & @PostConstruct、BeanPostProcessorsr)
@Component
publicclass Teacher implements InitializingBean,DisposableBean {
public Teacher() {
System.out.println("Teacher(ID) - 构造器................");
}
publicvoid afterPropertiesSet() throws Exception {
System.out.println("Teacher(ID) - bean属性复制和初始化完成时调用");
}
publicvoid destroy() throws Exception {
System.out.println("Teacher(ID) - destroy........");
}
}
|
@Component
publicclass Person {
public Person() {
System.out.println("Person JSR250 - 构造器................");
}
@PostConstruct
publicvoid afterPropertiesSet() {
System.out.println("Person JSR250 - bean属性复制和初始化完成时调用");
}
@PreDestroy
publicvoid destroy() {
System.out.println("Person JSR250 - destroy........");
}
}
|
@Component
publicclass Girl implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//返回传进来的对象,在初始化之前调用进行处理工作
System.out.println("Girl-Before:" + bean + " - " + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Girl-After:" + bean + " - " + beanName);
return bean;
}
}
|
/**
* ApplicationContextAware:获取到Spring的上下文
*/
@Component
publicclass Boy implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Boy() {
System.out.println("Boy 构造器................");
}
@PostConstruct
publicvoid afterPropertiesSet() {
System.out.println("Boy bean属性复制和初始化完成时调用");
}
@PreDestroy
publicvoid destroy() {
System.out.println("Boy destroy........");
}
@Override
publicvoid setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
|
@Configuration
@ComponentScan(value = "com.levi.spring.annotations.levi07initdestoryway")
publicclass MainConfig {
/**
* 定义和销毁的方式:
* 1、@Bean注解定义初始化和销毁的方法
* 2、实现InitializingBean接口的afterPropertiesSet()方法,但BeanFactory创建好对象,而且把Bean所有属性
* 都设置好了之后,会调用这个方法,相当于初始化方法。
* 实现DisposableBean的destroy()方法,当Bean销毁时,会把单实例Bean进行销毁。
* 3、根据JSR250规则定义的Java规范的两个注解来实现。
* @PostConstruct:在Bean创建完成,而且属于复制完成后进行初始化,属于JDK规范的注解。
* @PreDestroy:在Bean被移除之前进行通知,在容器销毁之前进行清理工作。
* JSR250是JDK提供的统一规范。
* 4、使用BeanPostProcessor控制Bean的生命周期,这种接近源码
*/
@Bean(initMethod = "init",destroyMethod = "destroy")
public Student student() {
returnnew Student();
}
publicstaticvoid main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Student student = (Student) applicationContext.getBean("student");
System.out.println(student);
applicationContext.close();
}
}
|
源码-Bean生命周期
AnnotationConfigApplicationContext:
publicstaticvoid main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Student student = (Student) applicationContext.getBean("student");
System.out.println(student);
applicationContext.close();
}
|
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
|
516行:refresh()
550行:finishBeanFactoryInitialization(beanFactory);
869行:beanFactory.preInstantiateSingletons();
740行:if (isFactoryBean(beanName)) à FactoryBean的定制化作用
760行:getBean(beanName);
199行:doGetBean(name, null, null, false); à (debug)246行
317行:createBean(beanName, mbd, args);
501行:doCreateBean(beanName, mbdToUse, args);
541行:createBeanInstance(beanName, mbd, args); à 完成bean的创建
550行:synchronized (mbd.postProcessingLock) à 后置处理程序
553行:applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
578行:populateBean(beanName, mbd, instanceWrapper); à 属性赋值
579行:initializeBean(beanName, exposedObject, mbd); à Bean初始化,并包括前后置方法的处理 {
1069行:wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); à
1702行:invokeInitMethods(beanName, wrappedBean, mbd); à 初始化方法
1710行:wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
ApplicationContextAware上下文获取
1、结合之前的Bean生命周期的源码,在debug中可以看到是多了几个方法。
2、会判断是否实现了ApplicationContextAware接口,是就会调用invokeAwareInterfaces注入值。
@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
returnnull;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
|
3、其他的前置、后置处理器都是一样的原理的,虽然是使用注解,但是背后原理是一样的。
总结:把Spring底层的组件可以注入到自定义的bean中,ApplicationContextAware是利用ApplicationContextAwareProcessor来处理的,其他的XXXAware也是类似的,都有相关的Processor来处理,其实就是后置处理器来处理。
@Value
publicclass Girl {
/**
* 直接复制
*/
@Value("Aimi")
private String name;
/**
* EL表达式
*/
@Value("#{10 - 1}")
privateint age;
/**
* 读取配置文件,如果读取不到这个配置,默认为abc
*/
@Value("${girl.desc:abc}")
private String desc;
@Override
public String toString() {
return "Girl [name=" + name + ", age=" + age + ", desc=" + desc + "]";
}
}
|
@Configuration
publicclass MainConfig {
@Bean
public Girl girl() {
returnnew Girl();
}
publicstaticvoid main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Girl girl = (Girl) applicationContext.getBean("girl");
System.out.println(girl);
}
}
|
自动装配(@Autowired、@Primary、@Resource、@Component、@Inject、@Quialifar、@Controller、@Service、@Repository)区别
@Repository
publicclass LeviDao {
private String name = "A";
public LeviDao() {
super();
}
public LeviDao(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
publicvoid setName(String name) {
this.name = name;
}
}
|
@Service
publicclass LeviService {
@Qualifier("leviDao") //寻找优先级最高的
@Autowired
// @Resource //不支持Primary、不支持Autowired=false
// @Inject //在不使用Spring的情况下,可以使用,不支持Autowired=false
private LeviDao leviDao;
publicvoid test() {
System.out.println("LeviService:" + leviDao.getName());
}
}
|
@Controller
publicclass LeviController {
@Autowired
private LeviService leviService;
}
|
@Configuration
@ComponentScan(value = "com.levi.spring.annotations.levi09automatically")
publicclass MainConfig {
/**
* 自动装配:Spring利用依赖注入,完成对IOC容器中的各个组件的依赖关系赋值。
* @Primary:标注注入IOC的类对象作为自动装配的首选,即优先级最高。如果在@Bean注入对象中,加入这个就说明了这个注入的优先级最高,
* 那么@Autowired的优先级不在是优先限定类名了。
* @Autowired:同一个类多个名称,默认优先限定类名,支持required=false,支持@Primary
* @Resource:效果和Autowired一样可以装配bean。1、不支持@Primary。2、不支持required=false的功能,即IOC容器中找不到会报错
* @Quialifar:指定ID,始终读取优先级最高的,相对于@Primary来说,@Primary减少了冗余,不用每次读取都指定
* @Inject:可以完成bean装配,这个是需要额外引入第三方的包javax.inject,功能和@Autowired差不多,支持@Primary,只是没有required=false,在没有用Spring框架时,可以用这个。
*
* @Component:是一个通用的注解,可以将java类标记为bean,可以是任何Spring管理组件的通用构造型。
* 而@Repository、@Service、@Controller都是@Component的扩展,从源码中可以看得出来。
* @Repository:源码依然是指向@Component,但是是标注在持久层的注解,具有将数据库操作抛出的原生异常翻译成Spring的持久层异常的功能。
* @Service:源码依然是指向@Component,是业务逻辑层的注解,只是标注该类位于业务逻辑层,不会对@Component注解提供任何其他行为。
* @Controller:源码依然是指向@Component,是SpringMVC的注解,具有将请求转发、重定向的功能。
*
* 如果IOC容器存在两个ID相同的Bean?会报错
* bean组件优先级?默认优先限定名
* 如何指定装配组件ID进行加载?@Qualifiar
* 容器加载不存在的bean会出现什么问题?@Autowired可以用required=false
* -@Primary注解bean首选如何使用?在注入的类的中位置加上这个@Primary注解
*/
//优先使用
@Primary
@Bean
public LeviDao leviDao2() {
returnnew LeviDao("B");
}
publicstaticvoid main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
LeviService leviService = annotationConfigApplicationContext.getBean(LeviService.class);
leviService.test();
System.out.println(annotationConfigApplicationContext.getBean(LeviDao.class).getName());
annotationConfigApplicationContext.close();
}
}
|
@Autowired
@Autowired的源码中可以看到用于构造器,用于方法。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() defaulttrue;
}
|
@Component
publicclass Teacher {
public Teacher() {
System.out.println("。。。C。。。Teacher。。。");
}
}
|
@Component
publicclass Person {
private Teacher teacher;
@Autowired
public Person(Teacher teacher) {
System.out.println("。。。C。。。Person。。。" + teacher);
}
@Autowired
publicvoid setTheacher(Teacher teacher) {
this.teacher = teacher;
}
public Teacher getTheacher() {
System.out.println("。。。M。。。Person。。。" + teacher);
returnthis.teacher;
}
}
|
@Configuration
@ComponentScan(value = "com.levi.spring.annotations.levi09automatically")
publicclass MainConfig {
//优先使用
@Primary
@Bean
public LeviDao leviDao2() {
returnnew LeviDao("B");
}
publicstaticvoid main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
//测试@Autowired构造器注入,查看对象地址是否是同一个即可
Teacher teacher = annotationConfigApplicationContext.getBean(Teacher.class);
System.out.println(teacher);
//测试@Autowired方法注入,查看对象地址是否是同一个即可
Person person = annotationConfigApplicationContext.getBean(Person.class);
System.out.println(person.getTheacher());
annotationConfigApplicationContext.close();
}
}
|
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。