Spring学习笔记之Spring IoC注解式开发

文章目录

  • 声明Bean的注解
    • Component注解
    • Controller注解
    • Service注解
    • Repository
  • Spring注解的使用
  • 选择性实例化Bean
  • 负责注入的注解
    • @Value
    • @Autowired与@Quaifier
    • @Resource
  • 全注解式开发

注解的存在主要是为了简化XML的配置。Spring6倡导全注解开发


  • 注解怎么定义,注解中的属性怎么定义?
  • 注解怎么使用
  • 通过反射机制怎么读取注解
    注解怎么定义,注解中的属性怎么定义?

package com.powernode.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Component {String value();
}

以上是自定义了一个注解:Component

该注解上面修饰的注解包括:Target注解和Retention注解,这两个注解被称为元注解。

Target注解用来设置Component注解可以出现的位置,以上代表表示Component注解只能用在类和接口上。

Retention注解用来设置Component注解的保持性策略,以上代表Component注解可以被反射机制读取。

String value();是Component注解中的一个属性。该属性类型String属性名是value。

//使用User
package com.powernode.bean;import com.powernode.annotation.Component;@Component(value = "userBean")
public class User {
}

语法格式:@注解类型名(属性名=属性值,属性名=属性值,属性名=属性值....)
userBean为什么使用双引号括起来,因为value属性是String类型,字符串

另外如果属性名是value,则在使用的时候可以省略属性名

package com.powernode.bean;import com.powernode.annotation.Component;//@Component(value = "userBean")
@Component("userBean")
public class User {
}

通过反射机制怎么读取注解?

//有注解的Bean
package com.powernode.bean;import com.powernode.annotation.Component;@Component("userBean")
public class User {
}
//没有注解的Bean
package com.powernode.bean;public class Vip {
}
//反射解析注解
package com.powernode.test;import com.powernode.annotation.Component;import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;/*** @author 动力节点* @version 1.0* @className Test* @since 1.0**/
public class Test {public static void main(String[] args) throws Exception {// 存放Bean的Map集合。key存储beanId。value存储Bean。Map<String,Object> beanMap = new HashMap<>();String packageName = "com.powernode.bean";String path = packageName.replaceAll("\\.", "/");URL url = ClassLoader.getSystemClassLoader().getResource(path);File file = new File(url.getPath());File[] files = file.listFiles();Arrays.stream(files).forEach(f -> {String className = packageName + "." + f.getName().split("\\.")[0];try {Class<?> clazz = Class.forName(className);if (clazz.isAnnotationPresent(Component.class)) {Component component = clazz.getAnnotation(Component.class);String beanId = component.value();Object bean = clazz.newInstance();beanMap.put(beanId, bean);}} catch (Exception e) {e.printStackTrace();}});System.out.println(beanMap);}
}

声明Bean的注解

负责声明Bean的注解,常见的包括四个

  • @Component
  • @Controller
  • @Service
  • @Respository

Component注解

package com.powernode.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Component {String value();
}

Controller注解

package org.springframework.stereotype;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;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {@AliasFor(annotation = Component.class)String value() default "";
}

Service注解

package org.springframework.stereotype;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;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {@AliasFor(annotation = Component.class)String value() default "";
}

Repository

package org.springframework.stereotype;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;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {@AliasFor(annotation = Component.class)String value() default "";
}

其实@Controller、@Service、@Repository这三个注解都是@Component注解的别名

也就是说:这四个注解的功能都一样,用哪个都可以
只是为了增强程序的可读性,建议

  • 控制类上使用:Controller
  • service类上使用:Service
  • dao类上使用Respsitory
    它们都是只有一个value属性。value属性用来指定bean的id,也就是bean的名字

Spring注解的使用

  • 第一步:加入aop的依赖
  • 第二步:在配置文件中添加context命名空间
  • 第三步:在配置文件中指定扫描的包
  • 第四步:在Bean类上使用注解

第一步:加入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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"></beans>

第三步:在配置文件中指定要扫描的包

<?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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.powernode.spring6.bean"/>
</beans>

第四步:在Bean类上使用注解

package com.powernode.spring6.bean;import org.springframework.stereotype.Component;@Component(value = "userBean")
public class User {
}
//test
package com.powernode.spring6.test;import com.powernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AnnotationTest {@Testpublic void testBean(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");User userBean = applicationContext.getBean("userBean", User.class);System.out.println(userBean);}
}

如果注解的属性名是value,那么value是可以省略的。

package com.powernode.spring6.bean;import org.springframework.stereotype.Component;@Component("vipBean")
public class Vip {
}
package com.powernode.spring6.test;import com.powernode.spring6.bean.Vip;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AnnotationTest {@Testpublic void testBean(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");Vip vipBean = applicationContext.getBean("vipBean", Vip.class);System.out.println(vipBean);}
}

如果把value属性彻底去掉,spring会被Bean自动取名,默认名字的规律是Bean类名首字母小写即可


如果是多个包怎么办?有两种解决方案:

  • 第一种:在配置文件中指定多个包,用逗号隔开
  • 第二种:指定多个包的共同父包

用逗号隔开

package com.powernode.spring6.bean2;import org.springframework.stereotype.Service;@Service
public class Order {
}
<?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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.powernode.spring6.bean,com.powernode.spring6.bean2"/>
</beans>

//test
package com.powernode.spring6.test;import com.powernode.spring6.bean.BankDao;
import com.powernode.spring6.bean2.Order;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AnnotationTest {@Testpublic void testBean(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");BankDao bankDao = applicationContext.getBean("bankDao", BankDao.class);System.out.println(bankDao);Order order = applicationContext.getBean("order", Order.class);System.out.println(order);}
}

指定父包

<?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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.powernode.spring6"/>
</beans>

选择性实例化Bean

假设在某个包下有很多Bean,有的Bean上标注了Component,有的标注了Controller,有的标注了Service,有的标注了Repository,现在由于某种特殊业务的需求,只允许其中所有的Controller参与Bean管理,其他的都不是实例化。该如何实现

package com.powernode.spring6.bean3;import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;@Component
public class A {public A() {System.out.println("A的无参数构造方法执行");}
}@Controller
class B {public B() {System.out.println("B的无参数构造方法执行");}
}@Service
class C {public C() {System.out.println("C的无参数构造方法执行");}
}@Repository
class D {public D() {System.out.println("D的无参数构造方法执行");}
}@Controller
class E {public E() {System.out.println("E的无参数构造方法执行");}
}@Controller
class F {public F() {System.out.println("F的无参数构造方法执行");}
}
<!-- spring-choose.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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.powernode.spring6.bean3" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan></beans>

其中:

use-default-filters="true"表示:使用spring默认的规则,只要有Compoment、Controller、Service、Repository中的任意一个注解标注,则进行实例化。

use-default-filters="false"标识:不再spring默认实例化规则,即使有Component、Controller、Service、Repository这些注解标注,也不再实例化.

<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>表示只有Controller进行实例化。

//test
@Test
public void testChoose(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-choose.xml");
}

也可以将use-default-filters设置为true(不写就是true),并且采用exclude-filter方式排除哪些注解标注的Bean不参与实例化:

<!-- spring-choose.xml -->
<context:component-scan base-package="com.powernode.spring6.bean3"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

负责注入的注解

@Component@Controller@Service@Repository这四个注解是用来声明Bean的,声明后这些Bean将被实例化。


给Bean属性赋值需要用到这些注解:

  • @Value
  • @Autowired
  • @Qualifier
  • @Resource

@Value

当属性的类型是简单类型时,可以使用@Value注解进行注入

//User
package com.powernode.spring6.bean4;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class User {@Value(value = "zhangsan")private String name;@Value("20")private int age;@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}

开启包扫描

<?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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.powernode.spring6.bean4"/>
</beans>
//test
@Test
public void testValue(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-injection.xml");Object user = applicationContext.getBean("user");System.out.println(user);
}

通过测试可以发现,我们并没有给属性提供setter方法,但仍然可以完成属性赋值
如果提供setter方法,并且再setter方法上添加@Value注解,更能完成此功能

package com.powernode.spring6.bean4;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class User {private String name;private int age;@Value("李四")public void setName(String name) {this.name = name;}@Value("30")public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}

@Value可以直接使用在属性上,也可以使用在setter方法上,都是可以的,都可以完成属性的赋值

为了简化代码,一般是不提供setter方法,直接在属性上使用@Value注解完成属性赋值。

package com.powernode.spring6.bean4;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class User {private String name;private int age;public User(@Value("隔壁老王") String name, @Value("33") int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}

@Value注解可以出现在属性上、setter方法上、以及构造方法的形参上。

@Autowired与@Quaifier

@Autowired注解可以用来注入非简单类型(翻译为:自动连线的,或者自动装配)

单独使用@Autowired注解,默认根据类型装配。(默认是byType)

//@Autowired源码
package org.springframework.beans.factory.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;@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {boolean required() default true;
}

源码中有两处需要注意:

  1. 该注解可以标注在哪里?
  • 构造方法上
  • 方法上
  • 形参上
  • 属性上
  • 注解上
  1. 该注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话也不报错

在属性上使用@Autowired注解

//
package com.powernode.spring6.dao;public interface UserDao {void insert();
}
package com.powernode.spring6.dao;import org.springframework.stereotype.Repository;@Repository //纳入bean管理
public class UserDaoForMySQL implements UserDao{@Overridepublic void insert() {System.out.println("正在向mysql数据库插入User数据");}
}
package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service // 纳入bean管理
public class UserService {@Autowired // 在属性上注入private UserDao userDao;// 没有提供构造方法和setter方法。public void save(){userDao.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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.powernode.spring6.dao,com.powernode.spring6.service"/>
</beans>
//test
@Test
public void testAutowired(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-injection.xml");UserService userService = applicationContext.getBean("userService", UserService.class);userService.save();
}

没有提供构造方法和setter方法,仍然可以注入成功


@Autowired注解出现在setter方法上

package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;@Autowiredpublic void setUserDao(UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}

@Autowired出现在构造方法上

package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;@Autowiredpublic UserService(UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}

@Autowired只标注在构造方法的形参上

package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;public UserService(@Autowired UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}

当参数的构造方法只有一个时,@Autowired注解可以省略

package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}

如果有多个构造方法,@Autowired肯定是不能省略的

package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}public UserService(){}public void save(){userDao.insert();}
}

@Autowired注解默认是byType进行注入的,也就是说根据类型注入的,
如果以上程序中,UserDao接口还有另外一个实现类,会出现什么问题

会提示出错:不能装配,UseDao这个Bean的数量大于一
怎么解决这个问题,当然要byName,根据名称进行装配。

@Autowired注解和@Qualifier注解联合起来才可以根据名称进行装配,在@Qualifier注解中指定Bean名称

package com.powernode.spring6.dao;import org.springframework.stereotype.Repository;@Repository // 这里没有给bean起名,默认名字是:userDaoForOracle
public class UserDaoForOracle implements UserDao{@Overridepublic void insert() {System.out.println("正在向Oracle数据库插入User数据");}
}
package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;@Autowired@Qualifier("userDaoForOracle") // 这个是bean的名字。public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}

总结:

  • @Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上。
  • 当带参数的构造方法只有一个,@Autowired注解可以省略
  • @Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用。

@Resource

@Resource注解也可以完成非简单类型注入。那它和@Autowired注解有什么区别

  • @Resource注解是JDK拓展包中的,也就是说属于JDK的一部分。所有该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
  • @Autowired注解是Spring框架自己的
  • @Resorce注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
  • @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用
  • @Resource注解用在属性上、setter方法上。
  • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上

@Resource注解属于JDK拓展包,所以不再JDK当中,需要额外引入以下依赖(如果时JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖):

<!-- spring-6 -->
<dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>2.1.1</version>
</dependency>

一定要注意:如果你用Spring6,要知道Spring6不再支持JavaEE,它支持的是JakartaEE9。
(Oracle把JavaEE贡献给Apache了,Apache把JavaEE的名字改成JaKartaEE了,所以之前所接触的所有javax.*包名统一修改为jakarta.*包名了)

<!-- spring-5 -->
<dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version>
</dependency>

package com.powernode.spring6.dao;import org.springframework.stereotype.Repository;@Repository("xyz")
public class UserDaoForOracle implements UserDao{@Overridepublic void insert() {System.out.println("正在向Oracle数据库插入User数据");}
}
package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;@Service
public class UserService {@Resource(name = "xyz")private UserDao userDao;public void save(){userDao.insert();}
}

把UseDaoForOracle的名字xyz修改为userDao,让这个Bean的名字和UserService类中的UseDao属性名一致:

package com.powernode.spring6.dao;import org.springframework.stereotype.Repository;@Repository("userDao")
public class UserDaoForOracle implements UserDao{@Overridepublic void insert() {System.out.println("正在向Oracle数据库插入User数据");}
}
package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;@Service
public class UserService {@Resourceprivate UserDao userDao;public void save(){userDao.insert();}
}

当@Resource注解使用时没有指定name的时候,还是根据name进行查找,这个name是属性名

当通过name找不到的时候,自然会启动byType进行注入。


package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;@Resourcepublic void setUserDao(UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}

setUserDao去掉set之后,将首字母小写userDao,userDao就是name

也可以指定name

package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;@Resource(name = "userDaoForMySQL")public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}

@Resource注解:默认byName注入,没有指定name时把属性名当作name,根据name找不到时,才会byType注入。byType注入时,某种类型的Bean只能有一个

全注解式开发

省略省略省略省略,还有这个,全部省略
所谓的全注解开发就是不再使用spring配置文件了。写一个配置类来代替配置文件

package com.powernode.spring6.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan({"com.powernode.spring6.dao", "com.powernode.spring6.service"})
public class Spring6Configuration {
}

编写test程序时不用再new ClassPathXmlApplicationContext()对象了

@Test
public void testNoXml(){ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class);UserService userService = applicationContext.getBean("userService", UserService.class);userService.save();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/40219.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入探索JavaEE单体架构、微服务架构与云原生架构

课程链接&#xff1a; 链接: https://pan.baidu.com/s/1xSI1ofwYXfqOchfwszCZnA?pwd4s99 提取码: 4s99 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; &#x1f50d;【00】模块零&#xff1a;开营直播&a…

ARM-M0内核MCU,内置24bit ADC,采样率4KSPS,传感器、电子秤、体脂秤专用,国产IC

ARM-M0内核MCU 内置24bit ADC &#xff0c;采样率4KSPS flash 64KB&#xff0c;SRAM 32KB 适用于传感器&#xff0c;电子秤&#xff0c;体脂秤等等

[BitSail] Connector开发详解系列三:SourceReader

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 Source Connector 本文将主要介绍负责数据读取的组件SourceReader&#xff1a; SourceReader 每个SourceReader都在独立的线程中执行&#xff0c;只要我们保证Sou…

Jmeter进阶使用:BeanShell实现接口前置和后置操作

一、背景 我们使用Jmeter做压力测试或者接口测试时&#xff0c;除了最简单的直接对接口发起请求&#xff0c;很多时候需要对接口进行一些前置操作&#xff1a;比如提前生成测试数据&#xff0c;以及一些后置操作&#xff1a;比如提取接口响应内容中的某个字段的值。举个最常用…

c语言——拷贝数组

这段代码是一个简单的数组拷贝示例。它的功能是将一个原始数组 original 的内容拷贝到另一个数组 copied 中&#xff0c;并输出两个数组的元素。 代码执行过程如下&#xff1a; 首先&#xff0c;在 main() 函数中定义了一个整型数组 original&#xff0c;并初始化了它的元素。…

【ARM 嵌入式 编译 Makefile 系列 15 - Makefile define 宏与调用宏函数详细介绍】

文章目录 Makefile define 宏与调用宏函数带参数的宏函数带返回值的宏函数Makefile define 宏与调用宏函数 在Makefile中,可以通过define关键字来定义一个多行的宏(也称为变量)。这种宏定义通常用于定义一个复杂的命令序列,然后在其他地方调用。 以下是定义一个宏的例子:…

物联网在制造业中的应用

制造业目前正在经历第四次工业革命&#xff0c;物联网、人工智能和机器人等技术进步正在推动行业的发展。研究表明&#xff0c;到2024年&#xff0c;全球制造商将在物联网解决方案上投资700亿美元&#xff0c;许多制造商正在实施物联网设备&#xff0c;以利用预测性维护和复杂的…

接口测试工具——Postman测试工具 Swagger接口测试+SpringBoot整合 JMeter高并发测试工具

目录 Postman测试工具接口测试工具swaggerKnife4j1.引入依赖2.配置3.常用注解4.接口测试 JMeter什么是JMeter?JMeter安装配置1.官网下载2.下载后解压3.汉语设置 JMeter的使用方法1.新建线程组2.设置参数3.添加取样器4.设置参数&#xff1a;协议&#xff0c;ip&#xff0c;端口…

SDK是什么,SDK和API有什么区别

SDK&#xff08;Software Development Kit&#xff09;是一种开发工具包&#xff0c;通常由软件开发公司或平台提供&#xff0c;用于帮助开发人员构建、测试和集成特定平台或软件的应用程序。SDK 包含一系列的库、工具、示例代码和文档&#xff0c;旨在简化开发过程并提供所需的…

基于Mysql+Vue+Django的协同过滤和内容推荐算法的智能音乐推荐系统——深度学习算法应用(含全部工程源码)+数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境MySQL环境VUE环境 模块实现1. 数据请求和储存2. 数据处理计算歌曲、歌手、用户相似度计算用户推荐集 3. 数据存储与后台4. 数据展示 系统测试工程源代码下载其它资料下载 前言 本项目以丰富的网易云音乐数据为基…

SQLSERVER 查询语句加with (NOLOCK) 报ORDER BY 报错 除非另外还指定了 TOP、OFFSET 或 FOR XML

最近有一个项目在客户使用时发现死锁问题&#xff0c;用的数据库是SQLSERVER &#xff0c;死锁的原因是有的客户经常去点报表&#xff0c;报表查询时间又慢&#xff0c;然后又有人在做单导致了死锁&#xff0c;然后主管要我们用SQLSERVER查询时要加with (NOLOCK),但是我在加完 …

YOLOv5模型训练流程

此文章只是记录使用&#xff0c;以便后续查看&#xff0c;不作为教程&#xff0c;刚接触&#xff0c;可能有错误 YOLOv5模型训练流程 一、数据集的准备 1.在源码根目录新建mydata文件夹&#xff0c;在此文件夹下新建images和labels文件夹 目录树如下&#xff1a; ├───…

链表---

题目描述 一个学校里老师要将班上 N 个同学排成一列&#xff0c;同学被编号为 1∼N&#xff0c;他采取如下的方法&#xff1a; 先将 11 号同学安排进队列&#xff0c;这时队列中只有他一个人&#xff1b; 2∼N 号同学依次入列&#xff0c;编号为 i 的同学入列方式为&#xff…

2023骨传导耳机推荐,适合运动骨传导耳机推荐

相信很多人跟我一样&#xff0c;随着现在五花八门的耳机品种增多&#xff0c;选耳机的时候真是眼花缭乱&#xff0c;尤其还是网购&#xff0c;只能看&#xff0c;不能试&#xff0c;所以选择起来比较困难&#xff0c; 作为一个运动达人&#xff0c;为了让大家在购买耳机时少走弯…

〔012〕Stable Diffusion 之 中文提示词自动翻译插件 篇

✨ 目录 &#x1f388; 翻译插件&#x1f388; 下载谷歌翻译&#x1f388; 谷歌翻译使用方法&#x1f388; 谷歌翻译使用效果 &#x1f388; 翻译插件 在插件列表中搜索 Prompt Translator可以看到有2个插件选项&#xff1a;一个是基于谷歌翻译 〔推荐〕、一个基于百度和deepl…

jvm从入门到精通

jvm 1.jvm与java体系结构​​​​​​​

奥威BI财务数据分析方案:借BI之利,成就智能财务分析

随着智能技术的发展&#xff0c;各行各业都走上借助智能技术高效运作道路&#xff0c;财务数据分析也不例外。借助BI商业智能技术能够让财务数据分析更高效、便捷、直观立体&#xff0c;也更有助于发挥财务数据分析作为企业经营管理健康晴雨表的作用。随着BI财务数据分析经验的…

【RP2040】香瓜树莓派RP2040之新建工程

本文最后修改时间&#xff1a;2022年09月05日 11:02 一、本节简介 本节介绍如何新建一个自己的工程。 二、实验平台 1、硬件平台 1&#xff09;树莓派pico开发板 ①树莓派pico开发板*2 ②micro usb数据线*2 2&#xff09;电脑 2、软件平台 1&#xff09;VS CODE 三、版…

【C++】一文带你初识C++继承

食用指南&#xff1a;本文在有C基础的情况下食用更佳 &#x1f340;本文前置知识&#xff1a; C类 ♈️今日夜电波&#xff1a;napori—Vaundy 1:21 ━━━━━━️&#x1f49f;──────── 3:23 …

CSS中的calc()函数有什么作用?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CSS中的calc()函数及其作用⭐ 作用⭐ 示例1. 动态计算宽度&#xff1a;2. 响应式布局&#xff1a;3. 自适应字体大小&#xff1a;4. 计算间距&#xff1a; ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点…