视频链接:
黑马程序员Spring注解开发教程,包含框架Spring+SpringMVC+SrpingTest+SpringData(事物)_哔哩哔哩_bilibili
1 目录层级
2 编写自定义beanName生成器
CustomeBeanNameGenerator.java
package class05.config;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.beans.Introspector;
import java.util.Map;
import java.util.Set;
/**
* @author:
* @date:2022/3/10
* @description:
*/
public class CustomeBeanNameGenerator implements BeanNameGenerator {
private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
@Override
public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
// 10.
String beanName = null;
// 1.判断当前bean的定义信息是否是注解的
if (beanDefinition instanceof AnnotatedBeanDefinition) {
// 2.把definition转成注解的bean定义信息
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
// 3.获取注解bean定义的元信息
AnnotationMetadata annotationMetadata = annotatedBeanDefinition.getMetadata();
// 4.获取定义信息中的所有注解
Set<String> types = annotationMetadata.getAnnotationTypes();
// 5.遍历types集合
for (String type : types) {
// 6.得到注解属性
//AnnotationAttributes attributes= AnnotationConfigUtils.attributesFor();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(type, false));
// 7.判断attributes是否为null,同事必须是@Component及其衍生注解(JSR250规范,JSR330规范)
/**
* 1. 去 AnnotationBeanNameGenerator.class复制
* private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
* 和
* if (attributes != null && this.isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
* Object value = attributes.get("value");
* if (value instanceof String) {
* String strVal = (String)value;
* if (StringUtils.hasLength(strVal)) {
* if (beanName != null && !strVal.equals(beanName)) {
* throw new IllegalStateException("Stereotype annotations suggest inconsistent component names: '" + beanName + "' versus '" + strVal + "'");
* }
*
* beanName = strVal;
* }
* }
* }
*
* 和
* protected boolean isStereotypeWithNameValue(String annotationType, Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes) {
* boolean isStereotype = annotationType.equals("org.springframework.stereotype.Component") || metaAnnotationTypes.contains("org.springframework.stereotype.Component") || annotationType.equals("javax.annotation.ManagedBean") || annotationType.equals("javax.inject.Named");
* return isStereotype && attributes != null && attributes.containsKey("value");
* }
*
*
* 在方法中定义String beanName=null;
*
* 复制buildDefaultBeanName方法
* */
if (attributes != null && this.isStereotypeWithNameValue(type, annotationMetadata.getMetaAnnotationTypes(type), attributes)) {
Object value = attributes.get("value");
// 8.判断value的值是否为String类型
if (value instanceof String) {
String strVal = (String) value;
// 9.判断value属性是否有值,没有值的时候抛出一个异常,有值的时候strVal赋值给 beanName
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
}
return beanName != null ? "myDefine_" + beanName : "myDefine_" + buildDefaultBeanName(beanDefinition);
}
private boolean isStereotypeWithNameValue(String annotationType, Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes) {
boolean isStereotype = annotationType.equals("org.springframework.stereotype.Component") || metaAnnotationTypes.contains("org.springframework.stereotype.Component") || annotationType.equals("javax.annotation.ManagedBean") || annotationType.equals("javax.inject.Named");
return isStereotype && attributes != null && attributes.containsKey("value");
}
protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return this.buildDefaultBeanName(definition);
}
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}
}
SpringConfiguration.java
package class05.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author:
* @date:2022/3/9
* @description:
*/
@Configuration
@ComponentScan(basePackages = "class05",nameGenerator = CustomeBeanNameGenerator.class)//扫描UserSerVice.java所在的包下的所有文件
public class SpringConfiguration {
//1.默认value/basePackageClasses 的情况下 被 @ComponentScan 修饰的类,它所处的包下的所有内容都会被扫描
//2.如果@ComponentScan指定了扫描的路径比如:“@ComponentScan(basePackageClasses = UserService.class)” 他就会扫描UserService.java所在的包下的文件,就不会再去扫描默认的被这个注解标注的类文件所处包下的所有文件。
}
AccountServiceImp1.java
package class05.service.AccountServiceImp;
import org.springframework.stereotype.Service;
import class05.service.AccountService;
/**
* @author:
* @date:2022/3/9
* @description:
*/
//@Service
@Service("accountServiceImp2")
public class AccountServiceImp1 implements AccountService {
@Override
public void deleteAccount() {
System.out.println("删除用户2");
}
}
UserServiceImp1.java
package class05.service.UserServiceImp;
import org.springframework.stereotype.Service;
import class05.service.UserService;
/**
* @author:
* @date:2022/3/9
* @description:
*/
@Service(value="userServiceImp3")
public class UserServiceImp1 implements UserService {
@Override
public void saveUser() {
System.out.println("保存用户3");
}
}
UserServiceImp2.java
package class05.service.UserServiceImp;
import org.springframework.stereotype.Service;
import class05.service.UserService;
/**
* @author:
* @date:2022/3/9
* @description:
*/
@Service(value="userServiceImp4")
public class UserServiceImp2 implements UserService {
@Override
public void saveUser() {
System.out.println("保存用户4");
}
}
AccountService.java
package class05.service;
public interface AccountService {
public abstract void deleteAccount();
}
UserService.java
package class05.service;
public interface UserService {
public abstract void saveUser();
}
3 SpringComponentScanTest.java(测试类)
import class05.config.SpringConfiguration;
import class05.service.AccountService;
import class05.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author:
* @date:2022/3/9
* @description:
*/
public class SpringComponentScanTest {
public static void main(String[] args) {
//1.创建容器,基于注解创建方式。
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("class05/config");
// 2.获取对象
UserService userService = ac.getBean("myDefine_userServiceImp3", UserService.class);
// 3.调用方法
userService.saveUser();
// 1.创建容器 传入被注解的类的字节码的方式
AnnotationConfigApplicationContext ac2 = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// 2.获取对象
AccountService accountService = ac2.getBean("myDefine_accountServiceImp2", AccountService.class);
// 3.调用方法
accountService.deleteAccount();
}
}
4 debug运行查看控制台log
有 myDefine_xxxx 的beanName字样了,说明我定义的beanName生成器成功生效了。
"C:\Program Files\Java\jdk1.8.0_301\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:61334,suspend=y,server=n -javaagent:C:\Users\Admin\.IntelliJIdea2018.2\system\captureAgent\debugger-agent.jar=file:/C:/Users/Admin/AppData/Local/Temp/capture.props -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_301\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_301\jre\lib\rt.jar;C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\test-classes;C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\classes;C:\Users\Admin\.m2\repository\org\springframework\spring-context\5.1.6.RELEASE\spring-context-5.1.6.RELEASE.jar;C:\Users\Admin\.m2\repository\org\springframework\spring-aop\5.3.16\spring-aop-5.3.16.jar;C:\Users\Admin\.m2\repository\org\springframework\spring-beans\5.3.16\spring-beans-5.3.16.jar;C:\Users\Admin\.m2\repository\org\springframework\spring-core\5.3.16\spring-core-5.3.16.jar;C:\Users\Admin\.m2\repository\org\springframework\spring-jcl\5.3.16\spring-jcl-5.3.16.jar;C:\Users\Admin\.m2\repository\org\springframework\spring-expression\5.3.16\spring-expression-5.3.16.jar;C:\Users\Admin\.m2\repository\org\springframework\boot\spring-boot-starter\2.6.4\spring-boot-starter-2.6.4.jar;C:\Users\Admin\.m2\repository\org\springframework\boot\spring-boot\2.6.4\spring-boot-2.6.4.jar;C:\Users\Admin\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.6.4\spring-boot-autoconfigure-2.6.4.jar;C:\Users\Admin\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.6.4\spring-boot-starter-logging-2.6.4.jar;C:\Users\Admin\.m2\repository\ch\qos\logback\logback-classic\1.2.10\logback-classic-1.2.10.jar;C:\Users\Admin\.m2\repository\ch\qos\logback\logback-core\1.2.10\logback-core-1.2.10.jar;C:\Users\Admin\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.17.1\log4j-to-slf4j-2.17.1.jar;C:\Users\Admin\.m2\repository\org\apache\logging\log4j\log4j-api\2.17.1\log4j-api-2.17.1.jar;C:\Users\Admin\.m2\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;C:\Users\Admin\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\Users\Admin\.m2\repository\org\yaml\snakeyaml\1.29\snakeyaml-1.29.jar;C:\Users\Admin\.m2\repository\org\springframework\boot\spring-boot-starter-test\2.6.4\spring-boot-starter-test-2.6.4.jar;C:\Users\Admin\.m2\repository\org\springframework\boot\spring-boot-test\2.6.4\spring-boot-test-2.6.4.jar;C:\Users\Admin\.m2\repository\org\springframework\boot\spring-boot-test-autoconfigure\2.6.4\spring-boot-test-autoconfigure-2.6.4.jar;C:\Users\Admin\.m2\repository\com\jayway\jsonpath\json-path\2.6.0\json-path-2.6.0.jar;C:\Users\Admin\.m2\repository\net\minidev\json-smart\2.4.8\json-smart-2.4.8.jar;C:\Users\Admin\.m2\repository\net\minidev\accessors-smart\2.4.8\accessors-smart-2.4.8.jar;C:\Users\Admin\.m2\repository\org\ow2\asm\asm\9.1\asm-9.1.jar;C:\Users\Admin\.m2\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;C:\Users\Admin\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\2.3.3\jakarta.xml.bind-api-2.3.3.jar;C:\Users\Admin\.m2\repository\jakarta\activation\jakarta.activation-api\1.2.2\jakarta.activation-api-1.2.2.jar;C:\Users\Admin\.m2\repository\org\assertj\assertj-core\3.21.0\assertj-core-3.21.0.jar;C:\Users\Admin\.m2\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;C:\Users\Admin\.m2\repository\org\junit\jupiter\junit-jupiter\5.8.2\junit-jupiter-5.8.2.jar;C:\Users\Admin\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.8.2\junit-jupiter-api-5.8.2.jar;C:\Users\Admin\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\Admin\.m2\repository\org\junit\platform\junit-platform-commons\1.8.2\junit-platform-commons-1.8.2.jar;C:\Users\Admin\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Users\Admin\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.8.2\junit-jupiter-params-5.8.2.jar;C:\Users\Admin\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.8.2\junit-jupiter-engine-5.8.2.jar;C:\Users\Admin\.m2\repository\org\junit\platform\junit-platform-engine\1.8.2\junit-platform-engine-1.8.2.jar;C:\Users\Admin\.m2\repository\org\mockito\mockito-core\4.0.0\mockito-core-4.0.0.jar;C:\Users\Admin\.m2\repository\net\bytebuddy\byte-buddy\1.11.22\byte-buddy-1.11.22.jar;C:\Users\Admin\.m2\repository\net\bytebuddy\byte-buddy-agent\1.11.22\byte-buddy-agent-1.11.22.jar;C:\Users\Admin\.m2\repository\org\objenesis\objenesis\3.2\objenesis-3.2.jar;C:\Users\Admin\.m2\repository\org\mockito\mockito-junit-jupiter\4.0.0\mockito-junit-jupiter-4.0.0.jar;C:\Users\Admin\.m2\repository\org\skyscreamer\jsonassert\1.5.0\jsonassert-1.5.0.jar;C:\Users\Admin\.m2\repository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;C:\Users\Admin\.m2\repository\org\springframework\spring-test\5.3.16\spring-test-5.3.16.jar;C:\Users\Admin\.m2\repository\org\xmlunit\xmlunit-core\2.8.4\xmlunit-core-2.8.4.jar;C:\Users\Admin\.m2\repository\org\springframework\spring-jdbc\5.1.6.RELEASE\spring-jdbc-5.1.6.RELEASE.jar;C:\Users\Admin\.m2\repository\org\springframework\spring-tx\5.3.16\spring-tx-5.3.16.jar;C:\Users\Admin\.m2\repository\mysql\mysql-connector-java\5.1.45\mysql-connector-java-5.1.45.jar;D:\installtool\IntelliJ IDEA 2018.2.7\lib\idea_rt.jar" SpringComponentScanTest
Connected to the target VM, address: '127.0.0.1:61334', transport: 'socket'
16:13:07.949 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\classes\class05\config\SpringConfiguration.class]
16:13:07.972 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7b49cea0
16:13:08.002 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
16:13:08.059 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\classes\class05\service\AccountServiceImp\AccountServiceImp1.class]
16:13:08.060 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\classes\class05\service\UserServiceImp\UserServiceImp1.class]
16:13:08.060 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\classes\class05\service\UserServiceImp\UserServiceImp2.class]
16:13:08.165 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
16:13:08.166 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
16:13:08.168 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
16:13:08.169 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
16:13:08.175 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springConfiguration'
16:13:08.179 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myDefine_accountServiceImp2'
16:13:08.180 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myDefine_userServiceImp3'
16:13:08.180 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myDefine_userServiceImp4'
保存用户3
16:13:08.209 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7bbc8656
16:13:08.209 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
16:13:08.214 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\classes\class05\service\AccountServiceImp\AccountServiceImp1.class]
16:13:08.215 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\classes\class05\service\UserServiceImp\UserServiceImp1.class]
16:13:08.215 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\Users\Admin\Desktop\AnnotationDemo\demos\demo5\target\classes\class05\service\UserServiceImp\UserServiceImp2.class]
Disconnected from the target VM, address: '127.0.0.1:61334', transport: 'socket'
16:13:08.220 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
16:13:08.220 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
16:13:08.221 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
16:13:08.222 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
16:13:08.222 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springConfiguration'
16:13:08.222 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myDefine_accountServiceImp2'
16:13:08.223 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myDefine_userServiceImp3'
16:13:08.223 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myDefine_userServiceImp4'
删除用户2
Process finished with exit code 0