共计 7865 个字符,预计需要花费 20 分钟才能阅读完成。
springboot 实战电商我的项目 mall4j(https://gitee.com/gz-yami/mall4j)
java 商城零碎源码
1. bean 注册
咱们有个 Person 类
public class Person {
private Integer age;
private String name;
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
@Override
public String toString() {return "Person [age=" + age + ", name=" + name + "]";
}
}
1.1 传统 bean 注册
新建 beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.opgame.spring.Person">
<property name="age" value="18"/>
<property name="name" value="张三"/>
</bean>
</beans>
应用 person 对象进行测试
@Test
public void testBean() {ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person)context.getBean("person");
System.out.println(person);
}
1.2 应用 annotation 代替 xml 注册
创立一个带有 @Configuration
的 java 类,应用 @Bean
进行注册
@Configuration // 通知 spring 这个是一个 config 类
public class BeansConfig {
// 给容器注册一个 bean,类型为返回值类型,默认 id 为办法名,在 bean 注解中设置 id
@Bean("person")
public Person person() {Person person = new Person();
person.setAge(20);
person.setName("李四");
return person;
}
}
应用 person 对象进行测试
@Test
public void testBean() {ApplicationContext context = new AnnotationConfigApplicationContext(BeansConfig.class);
Person person = (Person)context.getBean("person");
System.out.println(person);
}
2 exclude、include filter
在传统的 spring mvc 我的项目中为了使事务起效,咱们通常在 context.xml
进行exclude @Controller
类,在mvc.xml
进行include @Controller
, 当咱们应用一些第三方类库的时候,有时也须要对某些类进行排除扫码,那该怎么办呢?
2.1 传统 xml 排除与导入扫描类
context.xml(须要 context 命名空间)
<context:component-scan base-package="com.opgame">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
mvx.xml
<!-- use-default-filters 默认 ture,默认扫描 @Component @Repository @Service @Controller -->
<context:component-scan base-package="com.opgame" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
2.2 应用注解的模式排除与导入扫描类
@ComponentScan 注解应用
- value: 指定要扫描的包
- excludeFilters = Filter[]:指定扫描的时候依照什么规定排除那些组件
- includeFilters = Filter[]:指定扫描的时候只须要蕴含哪些组件
- useDefaultFilters:是否应用默认的 Filters
Filter
- FilterType.ANNOTATION:依照注解
- FilterType.ASSIGNABLE_TYPE:依照给定的类型
- FilterType.ASPECTJ:应用 ASPECTJ 表达式
- FilterType.REGEX:应用正则指定
- FilterType.CUSTOM:应用自定义规定
- classes:ANNOTATION、ASSIGNABLE_TYPE、CUSTOM 给定的类
- pattern:ASPECTJ、REGEX 给定的表达式
@Configuration // 通知 spring 这个是一个 config 类
@ComponentScan(value="com.opgame",useDefaultFilters=false,
includeFilters= {@Filter(type=FilterType.ANNOTATION,classes= {Controller.class})
},
excludeFilters= {@Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {PersonController.class})
})
public class BeansConfig{}
自定义规定
// 实现 org.springframework.core.type.filter.TypeFilter 接口
public class BeanTypeFilter implements TypeFilter{
/**
* @param metadataReader 获取被 spring 扫描到的以后类的元数据
* @param metadataReaderFactory 获取元数据的工厂,用于获取其余类的信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// 获取以后类注解元信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取以后类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取以后类的资源(类门路)Resource resource = metadataReader.getResource();
// 如果以后类名含有 person 则配胜利
if(classMetadata.getClassName().contains("person")) {return true;}
return false;
}
}
3. 作用域与懒加载
3.1 xml
<!-- 默认 scope="singleton" 单例 -->
<!-- lazy-init="true" 当须要用到的时候才创建对象,默认为 spring 初始化时创立 -->
<bean id="person" class="com.opgame.spring.Person" scope="singleton" lazy-init="true">
<property name="age" value="18"/>
<property name="name" value="张三"/>
</bean>
3.2 注解
@Lazy
@Scope("singleton")
@Bean("person")
public Person person() {Person person = new Person();
person.setAge(20);
person.setName("李四");
return person;
}
4 按条件注册
在有的时候,咱们编写框架,又或者编写代码,在不同环境时须要切换到不同的实现办法。那么在何时加载那品种的实现,spring 为咱们提供了这个注解
在 spring 中应用@Conditional
注解实现按需加载类。
@Conditional({LinuxCondition.class})
public Person person1() {Person person = new Person();
person.setAge(18);
person.setName("李小四");
return person;
}
// 实现 org.springframework.context.annotation.Condition 接口
public class LinuxCondition implements Condition{public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取 ioc 应用的 beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 获取类加载器
ClassLoader classLoader = context.getClassLoader();
// 获取以后环境
Environment environment = context.getEnvironment();
// 获取 bean 注册类
BeanDefinitionRegistry registry = context.getRegistry();
// 判断是否蕴含 person 对象
boolean hasPerson = registry.containsBeanDefinition("person");
if (!hasPerson) {return false;}
// 判断是否属于 linux 环境
if(environment.getProperty("os.name").contains("linux")) {return true;}
return false;
}
}
在启动程序时设置 vm arguments 也能够查看 Environment 相干的笔记
-Dos.name=linux
也能够在
在 spring boot 中,应用@ConditionalOnMissingBean(name="xxx")
@ConditionalOnMissingBean(xxx.class)
也能够判断当没有某些类或者办法的时候进行注册。
5. 应用 import 进行注册
现有多个类
class Blue {}
class Color {}
class Red {}
5.1 进行简略的注册
当咱们须要无参注册的时候,能够应用@import
进行注册如:
@Configuration
@Import({Blue.class,Red.class})
public class BeansConfig {}
其中 bean id 为类全名称 如com.opgame.spring.bean.Blue
com.opgame.spring.bean.Red
相当于
@Configuration
public class BeansConfig {@Bean("com.opgame.spring.bean.Blue")
public Blue blue() {return new Blue();
}
@Bean("com.opgame.spring.bean.Red")
public Red red() {return new Red();
}
}
5.2 应用 ImportSelector 进行类名注册
// 自定义逻辑返回须要导入的组件
// 实现 org.springframework.context.annotation.ImportSelector 接口
public class BeanImportSelector implements ImportSelector{
/**
* importingClassMetadata: 能够获取以后被标注 @Import 注解的所有注解元信息
* 即以后例子中 BeansConfig.class 的所有注解的元信息
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 不容许返回 null
return new String[] {"com.opgame.spring.bean.Blue","com.opgame.spring.bean.Red"};
}
}
@Configuration
@Import({BeanImportSelector.class})
public class BeansConfig {}
5.3 ImportBeanDefinitionRegistrar 注册一个 bean 到容器中
此时注册的是 BeanDefinition,也就是 bean 的定义信息,而 spring 会依据 bean 的定义信息,进行 bean 的注册!也就是此时并没有注册 bean!!!
// 实现 org.springframework.context.annotation.ImportBeanDefinitionRegistrar 接口
public class BeansImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{
/**
* importingClassMetadata:以后 config 类的注解信息(beansConfig)* registry:Bean 注册类,能够在此把所有须要增加到容器中的 bean 调用 BeanDefinitionRegistry.registerBeanDefinition()办法进行注册
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {boolean hasBlue = registry.containsBeanDefinition("com.opgame.spring.bean.Blue");
boolean hasRed = registry.containsBeanDefinition("com.opgame.spring.bean.Red");
// 如果有红色和蓝色,则注册一个 id 为 color 的 Color 对象
if (hasBlue && hasRed) {RootBeanDefinition beanDefinition = new RootBeanDefinition(Color.class);
registry.registerBeanDefinition("color", beanDefinition);
}
}
}
@Configuration
@Import({Blue.class,Red.class,BeansImportBeanDefinitionRegistrar.class})
public class BeansConfig {}
6 实现 FactoryBean<?> 接口注册 bean
// 实现 org.springframework.beans.factory.FactoryBean 接口
public class PersonFactoryBean implements FactoryBean<Person>{
// 结构 person 对象
public Person getObject() throws Exception {return new Person();
}
// 获取以后对象的类型
public Class<?> getObjectType() {return Person.class;}
// 是否为单例
public boolean isSingleton() {return true;}
}
@Configuration
public class BeansConfig {
@Bean
public PersonFactoryBean personFactoryBean() {return new PersonFactoryBean();
}
}
应用 person 对象进行测试
@Test
public void testBean() {ApplicationContext context = new AnnotationConfigApplicationContext(BeansConfig.class);
context.getBean("personFactoryBean").getClass(); // com.opgame.spring.Person
// 获取该工厂结构除的 bean 对象须要 & 符号
Person person = (Person)context.getBean("&personFactoryBean");
// 不应用 & 则获取工厂自身
PersonFactoryBean personFactoryBean = (PersonFactoryBean)context.getBean("personFactoryBean");
System.out.println(person);
}
7 通过 BeanDefinitionBuilder 创立
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
builder.addPropertyValue("id", 1);
builder.addPropertyValue("name", "李四");
registry.registerBeanDefinition("user", builder.getBeanDefinition());
springboot 实战电商我的项目 mall4j(https://gitee.com/gz-yami/mall4j)
java 商城零碎源码