注解赋值可以是方法_P7笔记,把Spring注解讲的明明白白
關注公眾號領取海量架構師資料
環境搭建
注解的方式是通過配置類的方式來注入組件,注解注入要比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?==?}@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即可: ... class>org.springframework.web.context.request.RequestContextListener ...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相關技術文章或行業資訊,歡迎大家關注和轉發文章!
總結
以上是生活随笔為你收集整理的注解赋值可以是方法_P7笔记,把Spring注解讲的明明白白的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uniapp 子组件 props拿不到数
- 下一篇: @value 静态变量_Spring注解