一、回顾注解
注解的存在主要是为了简化XML的配置
Spring6倡导全注解开发
我们来回顾一下:
第一:注解怎么定义,注解中的属性怎么定义?
第二:注解怎么使用?
第三:通过反射机制怎么读取注解?
package com.qiu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.annotation
* @date 2022-11-13-17:20
* @since 1.0
*
* @Target 标注注解的注解,元注解,用于定注解可以出现的位置
*
* @Target(value = {ElementType.TYPE,ElementType.FIELD}) 表示:
* Component 注解可以出现在类上、属性上
*
* 使用某个注解的时候,注解的属性名是 value 的话,value 可以省略
* @Target({ElementType.TYPE,ElementType.FIELD})
* 使用某个注解的时候,注解的属性值是 数组 的话,且只有一个元素,大括号可以省略
* @Target(ElementType.TYPE)
*
* @Retention(RetentionPolicy.SOURCE)
* @Retention 也是一个元注解,用来标注 @Component 注解最终保留的位置
*/
@Target(value = {ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value();
}
用法简单,语法格式:@注解类型名(属性名=属性值, 属性名=属性值, 属性名=属性值......)
userBean 为什么使用双引号括起来,因为 value 属性是 String 类型,字符串
另外如果属性名是 value,则在使用的时候可以省略属性名,例如:
//@Component(value = "userBean")
@Component("userBean")
class User{
}
通过反射机制怎么读取注解?
接下来,我们来写一段程序,当 Bean 类上有 Component 注解时,则实例化 Bean 对象,如果没有,则不实例化对象
我们准备两个Bean,一个上面有注解,一个上面没有注解
package com.qiu.bean;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.annotation
* @date 2022-11-13-17:36
* @since 1.0
*/
@Component("userBean")
public class User {
}
package com.qiu.bean;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.annotation
* @date 2022-11-13-17:37
* @since 1.0
*/
public class Vip {
}
假设我们现在只知道包名,至于这个包下有多少个Bean我们不知道;哪些Bean上有注解,哪些Bean上没有注解,这些我们都不知道,如何通过程序全自动化判断
package com.qiu.annotation;
import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.annotation
* @date 2022-11-13-17:39
* @since 1.0
*/
public class Test {
public static void main(String[] args) {
Map<String,Object> beanMap = new HashMap<>();
String packageName = "com.qiu.bean";
// String packagePath = packageName.replaceAll("\\.","/");
String packagePath = packageName.replace(".","/");
URL url = ClassLoader.getSystemClassLoader().getResource(packagePath);
String path = url.getPath();
// System.out.println(path);
File file = new File(path);
File[] files = file.listFiles();
Arrays.stream(files).forEach(f -> {
// System.out.println(f.getName().split("\\.")[0]);
String className = packageName + "." + f.getName().split("\\.")[0];
// 反射机制解析注解
Class<?> aClass = null;
try {
aClass = Class.forName(className);
if (aClass.isAnnotationPresent(Component.class)) {
// 获取注解
Component component = aClass.getAnnotation(Component.class);
String id = component.value();
// 创建对象
Object o = aClass.newInstance();
beanMap.put(id, o);
}
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println(beanMap);
}
}
运行结果:
二、声明 Bean 的注解
负责声明 Bean 的注解,常见的包括四个:
@Component
@Controller
@Service
@Repository
@Component 注解源码:
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;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
@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 类上使用:Repository
他们都是只有一个 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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
第三步:在配置文件中指定要扫描的包
<!-- 指定要扫描的包 -->
<context:component-scan base-package="org.qiu.spring.bean"/>
第四步:在Bean类上使用注解
package org.qiu.spring.bean;
import org.springframework.stereotype.Component;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-13-22:40
* @since 1.0
*/
@Component(value = "userBean")
public class User {
}
@Test
public void testBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
运行结果:
如果注解的属性名是value,那么value是可以省略的
如果把value属性彻底去掉,spring会给Bean自动取名,默认名字的规律是:Bean类名首字母小写即可
如果是多个包怎么办?有两种解决方案:
第一种:在配置文件中指定多个包,用逗号隔开
第二种:指定多个包的共同父包
方案一:在配置文件中指定多个包
<!-- 指定要扫描的包 -->
<context:component-scan base-package="org.qiu.spring.bean,org.qiu.spring.dao"/>
package org.qiu.spring.dao;
import org.springframework.stereotype.Component;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package org.qiu.spring.dao
* @date 2022-11-14-07:49
* @since 1.0
*/
@Component("userDao")
public class UserDao {
}
@Test
public void testBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
System.out.println(userDao);
}
运行结果:
方案二:指定共同的父包
<!-- 指定要扫描的包 -->
<context:component-scan base-package="org.qiu.spring"/>
运行效果:
四、选择性实例化 Bean
假设在某个包下有很多Bean,有的Bean上标注了Component,有的标注了Controller,有的标注了Service,有的标注了Repository,现在由于某种特殊业务的需要,只允许其中所有的Controller参与Bean管理,其他的都不实例化,应该怎么办呢?
package org.qiu.spring.bean2;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package org.qiu.spring.bean2
* @date 2022-11-14-07:57
* @since 1.0
*/
@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");
}
}
@Test
public void testChoose(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-choose.xml");
}
默认情况下:
<context:component-scan base-package="org.qiu.spring.bean2" />
运行结果:
选择性实例化Bean:
方式一:
<context:component-scan base-package="org.qiu.spring.bean2" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
use-default-filters="true" 表示:
使用spring默认的规则,只要有Component、Controller、Service、Repository中的任意一个注解标注,则进行实例化
use-default-filters="false" 表示:
不再spring默认实例化规则,即使有Component、Controller、Service、Repository这些注解标注,也不再实例化
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 表示只有Controller进行实例化
运行效果:
方式二:
也可以将use-default-filters设置为true(不写就是true),并且采用exclude-filter方式排出哪些注解标注的Bean不参与实例化:
<context:component-scan base-package="org.qiu.spring.bean2">
<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的属性赋值。给Bean属性赋值需要用到这些注解:
@Value
@Autowired
@Qualifier
@Resource
@Value
当属性的类型是简单类型时,可以使用@Value注解进行注入
使用 @Value 注解,可以不写 setter 方法
@Value注解可以出现在属性上、setter 方法上、以及构造方法的形参上
为了简化代码,以后我们一般不提供 setter 方法,直接在属性上使用 @Value 注解完成属性赋值
package org.qiu.spring.bean3;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package org.qiu.spring.bean3
* @date 2022-11-14-11:25
* @since 1.0
*/
@Component
public class MyDataSource implements DataSource {
@Value("com.mysql.cj.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring")
private String url;
@Value("root")
private String username;
@Value("mysql")
private String password;
@Override
public String toString() {
return "MyDataSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
// 省略实现 DataSource 接口的方法
}
<?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.qiu.spring.bean3"/>
</beans>
@Test
public void testDIByAnnotation(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-di-annotation.xml");
MyDataSource myDataSource = applicationContext.getBean("myDataSource", MyDataSource.class);
System.out.println(myDataSource);
}
运行效果:
@Autowired 和 @Qualifier
@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;
}
源码中有两处需要注意:
第一处:该注解可以标注在哪里?
构造方法上
方法上
形参上
属性上
注解上
第二处:该注解有一个 required 属性,默认值是 true,表示在注入的时候要求被注入的 Bean 必须是存在的,如果不存在则报错。如果 required 属性设置为 false,表示注入的 Bean 存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错
package com.qiu.dao;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.dao
* @date 2022-11-14-22:09
* @since 1.0
*/
public interface OrderDao {
void insert();
}
package com.qiu.dao.impl;
import com.qiu.dao.OrderDao;
import org.springframework.stereotype.Repository;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.dao.impl
* @date 2022-11-14-22:09
* @since 1.0
*/
@Repository
public class OrderDaoImplForMySql implements OrderDao {
@Override
public void insert() {
System.out.println("MySql 数据库正在保存订单信息......");
}
}
package com.qiu.service;
import com.qiu.dao.OrderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.service
* @date 2022-11-14-22:10
* @since 1.0
*/
@Service
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
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qiu"/>
</beans>
@Test
public void testAutowired(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowired.xml");
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
orderService.generate();
}
运行结果:
以上构造方法和 setter 方法都没有提供,经过测试,仍然可以注入成功
@Autowired 注解 可以出现在 setter 方法上、构造方法上
而且当参数的构造方法只有一个的时候,@Autowired 注解可以省略(如果有多个时不能省略)
@Autowired 注解默认是 byType 进行注入的,也就是说根据类型注入的,如果以上程序中,OrderDao接口还有另外一个实现类
当你写完这个新的实现类之后,此时IDEA工具已经提示错误信息了:
怎么解决这个问题呢?当然要byName,根据名称进行装配了
@Autowired 注解和 @Qualifier 注解联合起来才可以根据名称进行装配,在 @Qualifier 注解中指定 Bean 名称
package com.qiu.dao.impl;
import com.qiu.dao.OrderDao;
import org.springframework.stereotype.Repository;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.dao.impl
* @date 2022-11-14-22:23
* @since 1.0
*/
@Repository // 这里没有给 bean 起名字,默认为 orderDaoImplOracle
public class OrderDaoImplOracle implements OrderDao {
@Override
public void insert() {
System.out.println("Oracle 数据库正在保存订单信息......");
}
}
package com.qiu.service;
import com.qiu.dao.OrderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package com.qiu.service
* @date 2022-11-14-22:10
* @since 1.0
*/
@Service
public class OrderService {
@Autowired
@Qualifier("orderDaoImplForOracle")
private OrderDao orderDao;
public void generate(){
orderDao.insert();
}
}
@Test
public void testAutowired(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowired.xml");
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
orderService.generate();
}
运行结果:
总结:
@Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上
当带参数的构造方法只有一个,@Autowired注解可以省略
@Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用
@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 方法上、构造方法上、构造方法参数上
@Resource 注解属于 JDK 扩展包,所以不在 JDK 当中,需要额外引入以下依赖:【如果是 JDK8 的话不需要额外引入依赖高于 JDK11 或低于 JDK8 需要引入以下依赖】
<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.* 包名了
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
@Resource注解的源码如下:
package cn.qiu.dao;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package cn.qiu.dao
* @date 2022-11-15-09:19
* @since 1.0
*/
public interface StudentDao {
void deleteById();
}
package cn.qiu.dao.impl;
import cn.qiu.dao.StudentDao;
import org.springframework.stereotype.Repository;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package cn.qiu.dao.impl
* @date 2022-11-15-09:19
* @since 1.0
*/
@Repository
public class StudentDaoImplForMySql implements StudentDao {
@Override
public void deleteById() {
System.out.println("MySQL 数据库正在删除学生信息......");
}
}
package cn.qiu.service;
import cn.qiu.dao.StudentDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package cn.qiu.service
* @date 2022-11-15-09:20
* @since 1.0
*/
@Service
public class StudentService {
@Resource(name = "studentDaoImplForMySql")
private 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.qiu"/>
</beans>
@Test
public void testResource(){
ApplicationContext application = new ClassPathXmlApplicationContext("spring-resource.xml");
StudentService studentService = application.getBean("studentService", StudentService.class);
studentService.deleteStudent();
}
运行结果:
当 @Resource 注解使用时没有指定 name 的时候,还是根据 name 进行查找,这个 name 是属性名
当通过 name 找不到的时候,自然会启动 byType 进行注入,此时若 StudentDao 接口有多个实现类,就会报错
package cn.qiu.service;
import cn.qiu.dao.StudentDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package cn.qiu.service
* @date 2022-11-15-09:20
* @since 1.0
*/
@Service
public class StudentService {
@Resource
private StudentDao studentDao2;
public void deleteStudent(){
studentDao2.deleteById();
}
}
package cn.qiu.dao.impl;
import cn.qiu.dao.StudentDao;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package cn.qiu.dao.impl
* @date 2022-11-15-09:30
* @since 1.0
*/
@Repository
public class StudentDaoImplForOracle implements StudentDao {
@Override
public void deleteById() {
System.out.println("Oracle 数据库正在删除学生信息......");
}
}
六、全注解开发
所谓的全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件
package cn.qiu;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package cn.qiu
* @date 2022-11-15-09:38
* @since 1.0
*/
@Configuration
@ComponentScan({"cn.qiu.dao","cn.qiu.service"})
public class SpringConfig {
}
@Test
public void testNoXML(){
ApplicationContext application = new AnnotationConfigApplicationContext(SpringConfig.class);
StudentService studentService = application.getBean("studentService", StudentService.class);
studentService.deleteStudent();
}
运行结果:
一 叶 知 秋,奥 妙 玄 心