环境搭建
注解的形式是通过配置类的形式来注入组件,注解注入要比XML注入的形式简略,注解注入也须要在前者的根底上,增加一个spring-context的包,也是理论开发中罕用的形式。
筹备所需Jar包
Spring注解之组件注册
Spring提供了许多的注解配置,这样咱们就能够通过注解的形式实现组件的注册,下图就是Spring中常常应用到的注解。
@ComponentScan和@Configurable
原先xml的形式
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 要扫描的包 --> <context:component-scan base-package="model"></context:component-scan></beans>
应用配置类
@Configurable来标注该类为Spring中的配置类,@ComponentScan(“model”)是为该配置类指定要去扫描的参数。
package config;import org.springframework.beans.factory.annotation.Configurable;import org.springframework.context.annotation.ComponentScan;import model.Product;/** * @Configurable: 该注解是标注该类是配置类 * @ComponentScan:配置要扫描的包 * @author GaoYang */@Configurable@ComponentScan("model")public class MainConfig {}
@Component
应用该注解就能够将Java对象@Component注册到Ioc容器中,@Component注解要是给属性赋值要配合@Value注解为属性赋值。
/** @Componnt能够指定该对象的id,也能够不必指定 默认id为该类的类名首字母小写 */@Component("students")public class Student { @Value("01") private int sid; @Value("侯宁宁") private String name; @Value("男") private String sex;
配置类
/** * @Configurable: 该注解是标注该类是配置类 * @ComponentScan:配置要扫描的包 * @author GaoYang */@Configurable@ComponentScan("model")public class MainConfig {}
应用@Configuration注入
@Component("students")public class Student { @Value("01") private int sid; @Value("侯宁宁") private String name; @Value("男") private String sex; public Student() { super(); } public Student(int sid, String name, String sex) { super(); this.sid = sid; this.name = name; this.sex = sex; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "Student [sid=" + sid + ", name=" + name + ", sex=" + sex + "]"; }}
测试
@Bean
应用@Bean注解该能够在咱们的spring注册类里标注,创建对象的办法,能够通过一个返回值为该对象的办法去创立该对象,并通过结构器为该对象的属性进行赋值。
// 配置类@Configurable@ComponentScan("model")public class MainConfig { // 默认id为办法名 @Bean public Product product1() { return new Product("张三","hashd",1); } // 能够指定id @Bean("product2") public Product product2() { return new Product("张三","hashd",1); }}
Java-Bean对象
public class Product { private String name; private String price; private int num; public Product() { super(); } public Product(String name, String price, int num) { super(); this.name = name; this.price = price; this.num = num; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } @Override public String toString() { return "Product [name=" + name + ", price=" + price + ", num=" + num + "]"; }}
测试
@TypeFilter
@TypeFilter注解
是通过设置条件来过滤一些资源,咱们能够过滤一些资源不让它加载到ioc容器中。它的应用要在@ComponentScan这个注解中国去应用,通过excludeFilters参数传值,excludeFilters是一个数组,能够设定多个@TypeFilter。
@TypeFilter语法
@Configurable@ComponentScan(value = "model",excludeFilters = { // FilterType.ANNOTATION是通过注解的模式进行过滤 @Filter(type = FilterType.ANNOTATION,classes = {Controller.class}), // FilterType.ASSIGNABLE_TYPE 是通过给定的类型 @Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {Product.class}), // FilterType.ASPECTJ 依据正则表达式 @Filter(type = FilterType.ASPECTJ,classes = {""}), // FilterType.CUSTOM 应用自定义规定 @Filter(type = FilterType.CUSTOM,classes = {TypeFilterImp.class})})public class MainConfig { // @Bean == <bean></bean>}
@FilterType.CUSTOM自定义规定
应用自定义规定,咱们必须给它创立一个制订规定的类,这个类要去实现TypeFilter这个接口,并实现match这个办法,过滤器就会依据match办法的返回值加载,如果去ture就去过滤不满足条件的,如果为false则不会去加载!
/** * MetadataReader: 读取到的以后正在扫描的信息 * MetadataReaderFactory:能够获取到其余任何类的信息 */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 获取以后类注解的信息 AnnotationMetadata mr = metadataReader.getAnnotationMetadata(); // 获取以后正在扫描的类的信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); // 获取以后类的资源信息 Resource resource = metadataReader.getResource(); // 获取以后类的名字 String className = classMetadata.getClassName(); System.out.println("----"+className); // contains蕴含“er” if(className.contains("er")) { return true; } return false; }}
@Scope
Spring创建对象默认是单例的,应用@Scope来形容也就是scope=“singleton”,另外scope还有prototype、request、session、global session作用域。
各作用域的的作用
- singleton单例模式,全局有且仅有一个实例。(默认值)
- prototype原型模式,每次获取Bean的时候会有一个新的实例。
- request示意该针对每一次HTTP申请都会产生一个新的bean,同时该bean仅在以后HTTP request内无效,配置实例:
request、session、global session应用的时候首先要在初始化web的web.xml中做如下配置:
如果你应用的是Servlet 2.4及以上的web容器,那么你仅须要在web利用的XML申明文件web.xml中减少下述ContextListener即可:<web-app> ... <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> ...</web-app>
- session作用域示意该针对每一次HTTP申请都会产生一个新的bean,同时该bean仅在以后HTTP session内无效
- global session作用域相似于规范的HTTP Session作用域,不过它仅仅在基于portlet的web利用中才有意义。Portlet标准定义了全局Session的概念,它被所有形成某个 portlet web利用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范畴内。如果你在web中应用global session作用域来标识bean,那么web会主动当成session类型来应用。
案例演示
singleton
@Configurable@ComponentScan("model")public class MainConfig { /** * @Scope * prototype: 多实例的 @Scope("prototype") * singleton: 单实例的 @Scope("person") * request: 一次申请创立一个实例 * session: 同一个session创立一个实例 * @return */ @Scope("singleton") @Bean public Product product() { System.out.println("该实例已被创立"); return new Product("张三","hashd",1); }}
测试代码
public class text { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); System.out.println("Ioc容器已创立实现!"); Product bean1 = applicationContext.getBean(Product.class); Product bean2 = applicationContext.getBean(Product.class); System.out.println(bean1== bean2); }}
从下图能够看到,bean1 == bean2
Layz-bean
@Layz赖加载次要是针对的是单例模式下,单例模式下ioc容器初始化时,就将bean对象注入到了容器中,@Layz注解能够让容器创立时不去注册容器,而是等到第一次调用时才去注册bean对象。此时,创立的对象仍然是单例模式!
应用语法
// 配置类@Configurable@ComponentScan("model")public class MainConfig { /** * 懒加载: * 针对的是单实例的bean,默认在容器启动的时候创建对象 * 赖加载:容器启动时不创建对象,当第一次被调用时被创立 * */ @Lazy @Bean public Product product() { System.out.println("该实例已被创立"); return new Product("张三","hashd",1); }
测试
@Conditional
@Conditional注解是依据制订条件来进行注册,须要我创立配置条件的配置类,如果条件满足就进行注册,不满足就不去注册。
语法
配置类
@Configurablepublic class MainConfig { @Conditional({winCondition.class}) @Bean("wind") public Product wind() { System.out.println("该实例已被创立"); return new Product("张三","wind",1);}
条件类必须去实现Condition接口,并增加为实现的办法!
public class winCondition implements Condition{ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata arg1) { Environment environment = context.getEnvironment(); // 获取以后操作系统的名字 String property = environment.getProperty("os.name"); if(property.contains("Windows")) { return true; } return false; }}
案例
需要依据以后操作系统去注册组件。
// 配置类@Configurable@Import(Hero.class)public class MainConfig { // Windows零碎 @Conditional({winCondition.class}) @Bean("wind") public Product wind() { System.out.println("该实例已被创立"); return new Product("张三","wind",1); } // Linux零碎 @Conditional({linuxCondition.class}) @Bean("linux") public Product linux() { return new Product("李四","linux",2); }}
条件配置类
public class winCondition implements Condition{ // Windows零碎,返回true @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata arg1) { Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); if(property.contains("Windows")) { return true; } return false; }}
public class linuxCondition implements Condition{ /** * ConditionContext: 判断条件能应用上下文环境 * AnnotatedTypeMetadata: 正文信息 */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 是否Linux零碎 // 1、能获取到ioc应用的bean工厂 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 2、获取类加载器 ClassLoader clLoader = context.getClassLoader(); // 3、获取以后环境信息 Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); // 5、bean注册类 BeanDefinitionRegistry registry = context.getRegistry(); if(property.contains("Linux")) { return true; } return false;}
测试…
@import
- @Import只能用在类上 ,@Import通过疾速导入的形式实现把实例退出spring的IOC容器中
- 退出IOC容器的形式有很多种,@Import注解就绝对很牛皮了,@Import注解能够用于导入第三方包 ,当然@Bean注解也能够,然而@Import注解疾速导入的形式更加便捷
- @Import注解有三种用法
第一种用法:间接填class数组
间接填对应的class数组,class数组能够有0到多个。对应的import的bean都将退出到spring容器中,这些在容器中bean名称是该类的全类名 ,比方com.yc.类名
@Import({ 类名.class , 类名.class... })public class TestDemo {}
第二种用法:ImportSelector形式【重点】
这种形式的前提就是一个类要实现ImportSelector接口,如果我要用这种办法,指标对象是Myclass这个类,剖析具体如下:
创立Myclass类并实现ImportSelector接口
public class Myclass implements ImportSelector {//既然是接口必定要实现这个接口的办法 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[0]; }}// 剖析实现接口的selectImports办法中的:// 1、返回值: 就是咱们实际上要导入到容器中的组件全类名【重点 】// 2、参数: AnnotationMetadata示意以后被@Import注解给标注的所有注解信息【不是重点】// 须要留神的是selectImports办法能够返回空数组然而不能返回null,否则会报空指针异样!
以上剖析结束之后,具体用法步骤如下:
第一步:创立Myclass类并实现ImportSelector接口,这里用于演示就增加一个全类名给其返回值
public class Myclass implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{"com.yc.Test.TestDemo3"}; }}
第二步:编写TestDemo 类,并标注上应用ImportSelector形式的Myclass类
@Import({TestDemo2.class,Myclass.class})public class TestDemo { @Bean public AccountDao2 accountDao2(){ return new AccountDao2(); }}
第三步:编写打印容器中的组件测试类
** * 打印容器中的组件测试 */public class AnnotationTestDemo { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(TestDemo.class); //这里的参数代表要做操作的类 String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String name : beanDefinitionNames){ System.out.println(name); } }}
第三种用法:ImportBeanDefinitionRegistrar形式
同样是一个接口,相似于第二种ImportSelector用法,类似度80%,只不过这种用法比拟自定义化注册,具体如下:
public class Myclass2 implements ImportBeanDefinitionRegistrar {//该实现办法默认为空 @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { }}// 参数剖析:// 第一个参数:annotationMetadata 和之前的ImportSelector参数一样都是示意以后被@Import注解给标注的所有注解信息// 第二个参数示意用于注册定义一个bean
第二步:编写代码,自定义注册bean
public class Myclass2 implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { //指定bean定义信息(包含bean的类型、作用域...) RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo4.class); //注册一个bean指定bean名字(id) beanDefinitionRegistry.registerBeanDefinition("TestDemo4444",rootBeanDefinition); }}
第三步:编写TestDemo 类,并标注上应用ImportBeanDefinitionRegistrar形式的Myclass2类
@Import({TestDemo2.class,Myclass.class,Myclass2.class})public class TestDemo { @Bean public AccountDao2 accountDao222(){ return new AccountDao2(); }}
@FactoryBean
编写配置类
// 标记这是一个Spring配置类@Configurationpublic class SpringConfiguration { // 如果没有@Bean注解,则注入到容器中的id就是办法名(也就是myFactoryBean),然而如果显示的给了值,那么注入到容器中的就是factoryBean @Bean("factoryBean") public MyFactoryBean myFactoryBean(){ return new MyFactoryBean(); }}
测试类
public class SpringDemo { @Test public void springTest01() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class); // 容器中获取的Bean,实际上就是工厂Bean(MyFactoryBean通过getObject()办法返回的对象) Object factoryBean01 = context.getBean("factoryBean"); System.out.println("实际上注入到容器中的类型是:" + factoryBean01.getClass()); Object factoryBean02 = context.getBean("factoryBean"); System.out.println("注入到容器内的对象是否是单例:" + (factoryBean01 == factoryBean02)); Object factoryBean03 = context.getBean("&factoryBean"); System.out.println("如果想获取到MyFactoryBean的对象,应用&前缀:" + factoryBean03); // 输入打印Spring中的所有Bean名称 String[] beanDefinitionNames = context.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } }}
最初
感激你看到这里,文章有什么有余还请斧正,感觉文章对你有帮忙的话记得给我点个赞,每天都会分享java相干技术文章或行业资讯,欢送大家关注和转发文章!