当前位置: 首页 > news >正文

网站正在建设源码wordpress 发码插件

网站正在建设源码,wordpress 发码插件,外包做网站不满意,询广西南宁网站运营文章目录 【README】【1】基本概念#xff1a;Configuration与Bean【2】使用AnnotationConfigApplicationContext实例化spring容器【2.1】使用java配置简单构建spring容器【2.1.1】AnnotationConfigApplicationContext与Component及JSR-330注解类一起使用 【2.2】使用register… 文章目录 【README】【1】基本概念Configuration与Bean【2】使用AnnotationConfigApplicationContext实例化spring容器【2.1】使用java配置简单构建spring容器【2.1.1】AnnotationConfigApplicationContext与Component及JSR-330注解类一起使用 【2.2】使用register(Class?)以编程方式构建容器【2.2.1】AnnotationConfigApplicationContext#refresh()源码 【2.3】启用AnnotationConfigApplicationContext扫描功能【2.3.1】补充Configuration注解 【2.4】支持使用AnnotationConfigWebApplicationContext构建springweb容器 【3】组合基于java的配置【3.1】使用 Import注解组合多个配置类【3.1.1】对Import引入的BeanDefinition注入依赖装配Import注解引入的bean【3.1.2】全限定导入bean以便导航 【3.2】以xml配置为中心并使用component-scan元素扫描java配置类配置spring容器的2种方式【3.2.1】代码实践 【3.3】以java配置为中心并使用ImportResoure注解引入xml配置【3.3.1】代码实践 【3.4】使用PropertySource加载属性文件 【4】使用Bean注解【4.1】声明Bean【4.2】Bean标注方法返回的bean的装配注入依赖【4.3】接收生命周期回调【4.3.1】Bean注册的bean生命周期回调代码实践 【4.4】指定bean作用范围【4.4.1】使用Scope注解【4.4.2】查找方法注入Lookup method injection仅了解本文不展开【4.4.3】自定义bean的名称 【5】所有Configuration类使用CGLIB进行子类化【5.1】java配置类内部运行原理重要 【README】 本文内容总结自spring官方文档 spring-framework-reference 章节4.12【Java-based container configuration】 墙裂推荐 代码参见 github: springbootDiscover chapter00 1新增maven依赖因为 Configuration 与 Bean注解定义在org.springframework.context.annotation包下 dependenciesdependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion6.1.10/version/dependency/dependencies【1】基本概念Configuration与Bean 1java配置支持spirng容器的 核心组件是Configuration标注的类 。这些类主要包含Bean标注的方法这些方法定义springIOC容器管理对象的初始化配置以及实例化逻辑。 2使用Configuration标注的类表明这些类可以被spring IOC容器作为bean定义的数据源。 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class AppConfig {Beanpublic MyService myService() {return new MyServiceImpl();} }AppConfig等价于下面的xml配置 beansbean idmyService classcom.acme.services.MyServiceImpl/ /beans3Bean的角色 如上述代码所示 Bean扮演了 bean元素的角色 接下来我们介绍使用java配置创建spring容器的多种方法 【2】使用AnnotationConfigApplicationContext实例化spring容器 1下面章节描述spring的AnnotationConfigApplicationContext它是spring3引入的 2作为ApplicationContext的实现类AnnotationConfigApplicationContext不仅接收Configuration类作为输入也可以接受Component类以及被JSR-330注解标注的类 (JSR, Java Specification Request java规范请求 ) JSR-330注解介绍JSR-330注解就是支持java实现依赖注入的注解如 Inject Qualilfier参见spirng 使用JSR-330标准注解 github JSR-330: Dependency Injection for Java. Java Community Process: JSR 330: Dependency Injection for Java 3当Configuration类作为输入Configuration类本身会被注册为bean定义该类中所有被Bean标注的方法返回的bean也会注册为bean定义 当Component与JSR-330注解标注的类作为输入这些类也会被注册为bean定义并且假定在必要时这些类中使用依赖注入元注解如Autowired or Inject 【2.1】使用java配置简单构建spring容器 1与使用spring xml文件作为输入数据源实例化ClassPathXmlApplicationContext容器类似Configuration也可以作为输入数据源实例化AnnotationConfigApplicationContext容器即注解配置的spring容器基于注解实例化容器可以完全不使用xml文件 其实 ClassPathXmlApplicationContext 与 AnnotationConfigApplicationContext 是兄弟它们都是spring容器ApplicationContext的子类只不过配置信息加载的方式不同一个是xml文件一个是注解 【JavaBasedContainerMain】基于java配置的spring容器构建 public class JavaBasedContainerMain {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig00.class);HelloService helloService context.getBean(HelloService.class);helloService.sayHello(tom);} }【运行结果】 hello tom【AppConfig00】 Configuration类配置类 Configuration public class AppConfig00 {Beanpublic HelloService helloService() {return new HelloService();} }【HelloService】服务类 public class HelloService {public void sayHello(String user) {System.out.println(hello user);} }【2.1.1】AnnotationConfigApplicationContext与Component及JSR-330注解类一起使用 1AnnotationConfigApplicationContext不局限于与Configuration类一起使用任何 Component或 JSR330注解类也可以作为其构造参数传入。 【JavaBasedContainerUsingJsr330Main】 基于java的使用Jsr-330注解的容器 public class JavaBasedContainerUsingJsr330Main {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(Jsr330Service.class, Jsr330Depository.class);context.getBean(Jsr330Service.class).saveUser(zhangsan);} }注意 上述代码中 Jsr330Service与Jsr330Depository需要使用spring的依赖注入注解Autowire进行装配如果使用JSR-330注解如Qualifier会报错 【Jsr330Service】 package com.tom.chapter00.classwithjsr330;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;Component public class Jsr330Service {// Autowired是spring注解 这里不能使用 Qualifier (JSR-330注解)Autowiredprivate Jsr330Depository jsr330Depository;public void saveUser(String userName) {jsr330Depository.saveUser(userName);} }【Jsr330Depository】 package com.tom.chapter00.classwithjsr330;import org.springframework.stereotype.Component;Component public class Jsr330Depository {public void saveUser(String userName) {System.out.println(saveUser() name userName 成功);} }【2.2】使用register(Class?)以编程方式构建容器 1AnnotationConfigApplicationContext可以通过使用无参构造器进行实例化实例化后使用register方法进行配置 当使用编程方式构建容器时这个方法特别有用 【SpringContainerUsingAnnotationConfigApplicationContextNoArgConstructor】 使用AnnotationConfigApplicationContext无参构造器实例化注解配置spring容器 ; package com.tom.chapter00;import com.tom.chapter00.service.HelloService; import com.tom.chapter00.service.HelloService02; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class SpringContainerUsingAnnotationConfigApplicationContextNoArgConstructor {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();context.register(AppConfig00.class, AppConfig02.class); // 调用register()方法注册配置context.refresh(); // 注册完成后调用 refresh方法刷新 context.getBean(HelloService.class).sayHello(Musk);context.getBean(HelloService02.class).sayHello(Trump);} }【步骤】 使用register(Class?)以编程方式构建容器步骤 ; 步骤1首先使用AnnotationConfigApplicationContext无参构造器实例化spring容器步骤2调用register()方法注册配置查看源码可知这是在收集BeanDefinition步骤3注册完成后调用 refresh方法刷新查看源码可知根据BeanDefinition实例化bean 【运行效果】 HelloService#sayHell(): hello Musk HelloService2#sayHell(): hello Trump【AppConfig00】 Configuration public class AppConfig00 {Beanpublic HelloService helloService() {return new HelloService();} }【HelloService】 public class HelloService { public void sayHello(String user) {System.out.println(HelloService#sayHell(): hello user);} }【2.2.1】AnnotationConfigApplicationContext#refresh()源码 public void refresh() throws BeansException, IllegalStateException {this.startupShutdownLock.lock();try {this.startupShutdownThread Thread.currentThread();StartupStep contextRefresh this.applicationStartup.start(spring.context.refresh);this.prepareRefresh();ConfigurableListableBeanFactory beanFactory this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess this.applicationStartup.start(spring.context.beans.post-process);this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);beanPostProcess.end();this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (Error | RuntimeException var12) {if (this.logger.isWarnEnabled()) {this.logger.warn(Exception encountered during context initialization - cancelling refresh attempt: var12);}this.destroyBeans();this.cancelRefresh(var12);throw var12;} finally {contextRefresh.end();}} finally {this.startupShutdownThread null;this.startupShutdownLock.unlock();}}【2.3】启用AnnotationConfigApplicationContext扫描功能 1使用xml配置扫描注解标注的bean如下 beanscontext:component-scan base-packagecom.acme/ /beans上述xml配置spring将会扫描com.acme包中Component标注的类这些类被作为spring beanDefinition在容器中注册 2AnnotationConfigApplicationContext公开了scan()方法支持相同的组件扫描功能 【SpringContainerUsingAnnotationConfigApplicationContextScan】 package com.tom.chapter00;import com.tom.chapter00.service.HelloService02WithComponentAnnotation; import com.tom.chapter00.service.HelloServiceWithComponentAnnotation; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class SpringContainerUsingAnnotationConfigApplicationContextScan {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();context.scan(com.tom.chapter00.service); // 调用scan()方法收集BeanDefinitioncontext.refresh(); // 根据BeanDefinition实例化bean context.getBean(HelloServiceWithComponentAnnotation.class).sayHello(Musk);context.getBean(HelloService02WithComponentAnnotation.class).sayHello(Trump);} }【步骤】 AnnotationConfigApplicationContext使用组件扫描实例化bean 步骤1首先使用AnnotationConfigApplicationContext无参构造器实例化注解配置spring容器步骤2调用scan()方法扫描指定包下BeanDefinition查看源码可知这是在收集BeanDefinition步骤3注册完成后调用 refresh方法刷新查看源码可知根据BeanDefinition实例化bean 【执行效果】 HelloServiceWithComponentAnnotation#sayHello: hello Musk HelloService02WithComponentAnnotation#sayHello: 02 hello Trump【HelloServiceWithComponentAnnotation】 package com.tom.chapter00.service;import org.springframework.stereotype.Component;Component public class HelloServiceWithComponentAnnotation {public void sayHello(String user) {System.out.println(HelloServiceWithComponentAnnotation#sayHello: hello user);} }【2.3.1】补充Configuration注解 1Configuration使用Component注解的注解而Component称为元注解因为它是标注其他注解的注解 因此Configuration类可以被scan()扫描到 假设Configuration类声明在com.a.b.c包下及任意子包下AnnotationConfigApplicationContext容器在调用scan()方法时会扫描到该Configuration类而调用refresh()方法时Configuration类中被Bean标注的方法会被处理把方法返回值注册为容器中的bean 【SpringContainerUsingAnnotationConfigApplicationContextScanConfiguration】 扫描Configuration类 扫描com.tom.chapter00包及其子包下Component及Configuration类 public class SpringContainerUsingAnnotationConfigApplicationContextScanConfiguration {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();System.out.println(before scan());context.scan(com.tom.chapter00);System.out.println(after scan());System.out.println(before refresh());context.refresh();System.out.println(after refresh());context.getBean(HelloService02.class).sayHello(Musk);} }【执行效果】 before scan() after scan() before refresh() AppConfig00 构造器 AppConfig02 构造器 after refresh() HelloService2#sayHell(): hello Musk 【AppConfig02】 Configuration类包名为com.tom.chapter00.config是com.tom.chapter00的子包 package com.tom.chapter00.config;import com.tom.chapter00.service.HelloService02; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class AppConfig02 {public AppConfig02() {System.out.println(AppConfig02 构造器);}Beanpublic HelloService02 helloService02() {return new HelloService02();} } 【HelloService02】 public class HelloService02 {public void sayHello(String user) {System.out.println(HelloService2#sayHell(): hello user);} }【2.4】支持使用AnnotationConfigWebApplicationContext构建springweb容器 1AnnotationConfigApplicationContext的WebApplicationContext变体可以与AnnotationConfigWebApplicationContext一起使用 当配置spring ContextLoaderListener servlet监听器springmvc DispatcherServlet等可以使用AnnotationConfigWebApplicationContext作为参数 2以下web.xml代码片段配置了一个典型的springmvc web容器 web-app!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContextinstead of the default XmlWebApplicationContext --context-paramparam-namecontextClass/param-nameparam-valueorg.springframework.web.context.support.AnnotationConfigWebApplicationContext/param-value/context-param!-- Configuration locations must consist of one or more comma- or space-delimitedfully-qualified Configuration classes. Fully-qualified packages may also bespecified for component-scanning --context-paramparam-namecontextConfigLocation/param-nameparam-valuecom.acme.AppConfig/param-value/context-param!-- Bootstrap the root application context as usual using ContextLoaderListener --listenerlistener-classorg.springframework.web.context.ContextLoaderListener/listener-class/listener!-- Declare a Spring MVC DispatcherServlet as usual --servletservlet-namedispatcher/servlet-nameservlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContextinstead of the default XmlWebApplicationContext --init-paramparam-namecontextClass/param-nameparam-valueorg.springframework.web.context.support.AnnotationConfigWebApplicationContext/param-value/init-param!-- Again, config locations must consist of one or more comma- or space-delimitedand fully-qualified Configuration classes --init-paramparam-namecontextConfigLocation/param-nameparam-valuecom.acme.web.MvcConfig/param-value/init-param/servlet!-- map all requests for /app/* to the dispatcher servlet --servlet-mappingservlet-namedispatcher/servlet-nameurl-pattern/app/*/url-pattern/servlet-mapping /web-app【3】组合基于java的配置 【3.1】使用 Import注解组合多个配置类 1Import注解支持从其他配置类加载bean Definition就像在xml文件中使用 import元素来帮助模块化配置一样 【ImportAnnotationMain】Import注解测试main package com.tom.chapter00.config.importannotation;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class ImportAnnotationMain {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfigB.class);context.getBean(DiyA.class).print();} }代码说明 在实例化AnnotationConfigApplicationContext容器时无需指定AppConfigA.class与AppConfigB.class 而仅需要指定AppConfigB.class即可 因为AppConfigB 通过Import注解引入了 AppConfigA中的BeanDefinition 【AppConfigA】 package com.tom.chapter00.config.importannotation;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class AppConfigA { Beanpublic DiyA diyA() {return new DiyA();} }public class DiyA {public void print() {System.out.println(this is diy a);} }【AppConfigB】 Configuration Import(AppConfigA.class) // AppConfigB使用Import引入或导入AppConfigA public class AppConfigB {Beanpublic DiyB diyB() {return new DiyB();} }public class DiyB {public void print() {System.out.println(this is diy b);} } 【3.1.1】对Import引入的BeanDefinition注入依赖装配Import注解引入的bean 1大多数场景中一个Configuration配置类A中的Bean依赖另一个Configuration配置类B中的bean 这在xml配置文件中很好解决只需要配置类A中的bean元素使用ref元素引入配置类B的bean即可 2通过java配置的容器中需要使用类似于ref元素的语法对Import引入的bean进行装配 注意 Configuration标注的配置类始终是一个bean这意味着我们可以使用 Autowire注入元数据即装配Configuration类 【ImportAnnotationInjectDependencyMain】 public class ImportAnnotationInjectDependencyMain {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(SystemConfig01.class);context.getBean(UserService.class).saveUser(Trump);} }【配置类】 Configuration Import({UserServiceConfig.class, UserRepositoryConfig.class}) public class SystemConfig01 { }Configuration public class UserServiceConfig {private Autowired UserRepository userRepository; // 这个repository依赖于另一个配置类UserRepositoryConfig中的bean public Bean UserService userService() {return new UserService(userRepository);} }Configuration public class UserRepositoryConfig {public Bean UserRepository userRepository() {return new UserRepository(); } }【业务bean】 public class UserService {private UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository userRepository;}public void saveUser(String name) {userRepository.saveUser(name);} } public class UserRepository {public void saveUser(String name) {System.out.println(UserRepository#saveUser() 保存用户成功 name name);} }【3.1.2】全限定导入bean以便导航 13.1.1中的问题 UserServiceConfig使用Autowired装配UserRepository但这个UserRepository具体定义在哪个Configuration类是不清楚的这不利于类的导航查找 解决方法明确装配的bean所属的配置类考虑装配另一个配置类B本身到当前配置类A; 【UserServiceConfig2】 修改后的版本使用另一个配置类本身装配当前配置类 Configuration public class UserServiceConfig2 {// 装配的是Configuration类的bean而不是具体的Repository beanprivate Autowired UserRepositoryConfig userRepositoryConfig; public Bean UserService userService() {return new UserService(userRepositoryConfig.userRepository());} }【UserServiceConfig】之前的版本使用具体bean装配当前配置类 Configuration public class UserServiceConfig {private Autowired UserRepository userRepository;public Bean UserService userService() {return new UserService(userRepository);} }2 UserServiceConfig2中的代码还有点问题 UserServiceConfig2 与 UserRepositoryConfig高度耦合了 解决方法Autowired UserRepositoryConfig userRepositoryConfig修改 UserRepositoryConfig 为抽象定义如接口或抽象类 【ImportAnnotationInjectDependencyMain03】 public class ImportAnnotationInjectDependencyMain03 {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(SystemConfig03.class);context.getBean(UserService.class).saveUser(Trump);} }【总配置类-SystemConfig03】 引入的UserRepositoryConfigImpl是IUserRepositoryConfig接口的实现类 Configuration // 导入的是用户仓库配置接口的实现类的class而非其接口IUserRepositoryConfig的class Import({UserServiceConfig3.class, UserRepositoryConfigImpl.class}) public class SystemConfig03 { }【其他配置类】 Configuration public class UserServiceConfig3 {// 这里的属性类型为接口非具体实现以解耦private Autowired IUserRepositoryConfig userRepositoryConfig; public Bean UserService userService() { return new UserService(userRepositoryConfig.userRepository());} } // 用户仓库配置接口定义 public interface IUserRepositoryConfig { public UserRepository userRepository(); } // 用户仓库配置接口的实现类 public class UserRepositoryConfigImpl implements IUserRepositoryConfig { Overridepublic UserRepository userRepository() {return new UserRepository();} } 【3.2】以xml配置为中心并使用component-scan元素扫描java配置类配置spring容器的2种方式 1spring提供的Configuration配置类的支持并不是100%替换xml配置xml配置也有一些优点如xml命名空间就是一种完美的配置容器的方式 2配置spring容器有2种方式 使用xml文件方式且spring容器使用ClassPathXmlApplicationContext类使用java配置方式且spring容器使用AnnotationConfigApplicationContext 类且可以按需使用ImportResource注解引入xml配置文件 【3.2.1】代码实践 【ComposeJavaAndXmlMain】 public class ComposeJavaAndXmlMain {public static void main(String[] args) {ApplicationContext container new ClassPathXmlApplicationContext(chapter00/beans00.xml);container.getBean(ComposeJavaAndXmlService.class).saveUser(Trump);} }【执行效果】 ComposeJavaAndXmlRepository#saveUser(): nameTrump, urlwww.baidu.com【beans00.xml】 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdbeans!-- 扫描Component注解标注的类包括Configuration注册到spring容器 --context:component-scan base-packagecom.tom.chapter00.composejavaandxml/context:property-placeholder locationclasspath:/chapter00/jdbc.properties/bean classcom.tom.chapter00.composejavaandxml.ComposeJavaAndXmlRepositoryproperty nameurl value${jdbc.url}//bean/beans /beans【/chapter00/jdbc.properties】 属性文件 jdbc.urlwww.baidu.com【ComposeJavaAndXmlService】 public class ComposeJavaAndXmlService {private ComposeJavaAndXmlRepository composeJavaAndXmlRepository;public ComposeJavaAndXmlService(ComposeJavaAndXmlRepository composeJavaAndXmlRepository) {this.composeJavaAndXmlRepository composeJavaAndXmlRepository;}public void saveUser(String name) {composeJavaAndXmlRepository.saveUser(name);} }【ComposeJavaAndXmlRepository】 public class ComposeJavaAndXmlRepository {private String url;public void saveUser(String name) {System.out.println(ComposeJavaAndXmlRepository#saveUser(): name name , url url);}public String getUrl() {return url;}public void setUrl(String url) {this.url url;} }【补充】文件目录结构 【3.3】以java配置为中心并使用ImportResoure注解引入xml配置 1在spring应用中 Configuration注解配置spring容器是主要方式但仍然有可能使用到xml配置可以通过ImportResoure注解引入xml配置 【3.3.1】代码实践 【ImportResourceComposeJavaAndXmlMain】 public class ImportResourceComposeJavaAndXmlMain {public static void main(String[] args) {AnnotationConfigApplicationContext container new AnnotationConfigApplicationContext(UserRepositoryConfigUsingImportResource.class);container.getBean(ComposeJavaAndXmlRepository.class).saveUser(Trump);} }【执行效果】 ComposeJavaAndXmlRepository#saveUser(): nameTrump, urlwww.baidu.com【UserRepositoryConfigUsingImportResource】 使用 ImportResource引入xml配置的配置类 Configuration ImportResource(classpath:/chapter00/beans01.xml) public class UserRepositoryConfigUsingImportResource {private Value(${jdbc.url}) String url;public Bean ComposeJavaAndXmlRepository composeJavaAndXmlRepository() {ComposeJavaAndXmlRepository composeJavaAndXmlRepository new ComposeJavaAndXmlRepository();composeJavaAndXmlRepository.setUrl(url);return composeJavaAndXmlRepository;} }【beans01.xml】 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdbeanscontext:property-placeholder locationclasspath:/chapter00/jdbc.properties//beans /beans【jdbc.properties】 jdbc.urlwww.baidu.com【3.4】使用PropertySource加载属性文件 1使用PropertySource加载属性文件以访问所有定义的属性 【属性文件】 // kafka.properties kafka.cluster.url192.168.1.1 kafka.cluster.nameTomKafka// redis.properties redis.cluster.url192.168.1.2 redis.cluster.nameTomRedis【属性文件路径】 【PropertySourceMain】 public class PropertySourceMain {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(PropertySourceConfig.class);// 获取beanTomCluster tomCluster context.getBean(TomCluster.class);System.out.println(tomCluster);System.out.println(tomCluster.getKafkaClusterUrl());// 通过Environment获取属性ConfigurableEnvironment env context.getEnvironment();System.out.println(env.getProperty(kafka.cluster.name));System.out.println(env.getProperty(kafka.cluster.url));System.out.println(env.getProperty(redis.cluster.name));System.out.println(env.getProperty(redis.cluster.url));} }【运行效果】 TomCluster{kafkaClusterUrl192.168.1.1, kafkaClusterNameTomKafka, redisClusterUrl192.168.1.2, redisClusterNameTomRedis} 192.168.1.1 TomKafka 192.168.1.1 TomRedis 192.168.1.2【PropertySourceConfig】 package com.tom.chapter00.propertysource;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource;Configuration PropertySource(value {classpath:chapter00/kafka.properties, classpath:chapter00/redis.properties}) public class PropertySourceConfig {Beanpublic TomCluster tomCluster() {return new TomCluster();} } 【TomCluster】 package com.tom.chapter00.propertysource;import org.springframework.beans.factory.annotation.Value;public class TomCluster {Value(${kafka.cluster.url}) private String kafkaClusterUrl;Value(${kafka.cluster.name})private String kafkaClusterName;Value(${redis.cluster.url})private String redisClusterUrl;Value(${redis.cluster.name})private String redisClusterName;public String getKafkaClusterUrl() {return kafkaClusterUrl;}public String getKafkaClusterName() {return kafkaClusterName;}public String getRedisClusterUrl() {return redisClusterUrl;}public String getRedisClusterName() {return redisClusterName;}Overridepublic String toString() {return TomCluster{ kafkaClusterUrl kafkaClusterUrl \ , kafkaClusterName kafkaClusterName \ , redisClusterUrl redisClusterUrl \ , redisClusterName redisClusterName \ };} }【4】使用Bean注解 1Bean注解定义 Bean注解类似于xml文件中的bean元素该注解支持bean元素的一些属性如inin-method , destory-method, autowiring ,name 等。你可以在 Configuration类或Component类中使用 Bean注解 【4.1】声明Bean 1可以使用Bean标注一个方法以此来定义bean 你使用这个方法在ApplicationContext中注册bean的定义 bean类型指定为方法返回类型 默认情况下方法名称就是bean名称 【BeanAnnotationMain】 public class BeanAnnotationMain {public static void main(String[] args) {AnnotationConfigApplicationContext container new AnnotationConfigApplicationContext(BeanAnnotationConfig.class);System.out.println(container.getBean(UserService.class));System.out.println(container.getBean(userService));} } // com.tom.chapter00.config.importannotation.injectdependency.UserService6aeb35e6 // com.tom.chapter00.config.importannotation.injectdependency.UserService6aeb35e6container.getBean(“userService”) 与 container.getBean(UserService.class) 获取的是同一个bean所以UserService userService()方法注册的bean的名称就是方法名称userService 【BeanAnnotationConfig】 package com.tom.chapter00.beanannotation;import com.tom.chapter00.config.importannotation.injectdependency.UserService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class BeanAnnotationConfig {Beanpublic UserService userService() {return new UserService();} } 【4.2】Bean标注方法返回的bean的装配注入依赖 1当Bean注册的bean依赖另一个bean时仅需要调用另一个bean的注册方法即可注入依赖如下 【BeanAnnotationMain2】 public class BeanAnnotationMain2 {public static void main(String[] args) {AnnotationConfigApplicationContext container new AnnotationConfigApplicationContext(BeanAnnotationConfig2.class);System.out.println(container.getBean(repositoryA));container.getBean(ServiceA.class).printRepository();} }【执行效果】 显然 容器中名为repositoryA的bean与ServiceA中装配的类型为RepositoryA的bean是同一个bean com.tom.chapter00.beanannotation.repository.RepositoryA4c583ecf repositoryAcom.tom.chapter00.beanannotation.repository.RepositoryA4c583ecf 【BeanAnnotationConfig2】配置类 调用方法即可注入依赖 Configuration public class BeanAnnotationConfig2 {public Bean RepositoryA repositoryA() {return new RepositoryA();}public Bean ServiceA serviceA() {return new ServiceA(repositoryA()); // 调用方法即可注入依赖} }【ServiceA】 public class ServiceA {private RepositoryA repositoryA;public ServiceA(RepositoryA repositoryA) {this.repositoryA repositoryA;}public void printRepository() {System.out.println(repositoryA repositoryA);} }【4.3】接收生命周期回调 1任何使用Bean定义的类都可以使用 来自JSR-250的PostConstruct 与 PreDestory注解 参见 JSR-250的PostConstruct 与 PreDestory注解 2spring支持bean的生命周期回调如果bean实现了InitializingBean DisposableBean或者 Lifecycle 它们对应的方法就会被容器调用 以Aware为后缀的标准接口集合也支持生命周期回调如BeanFactoryAware, BeanNameAware, MessageSourceAware, ApplicationContextAware 3Bean注解支持指定任意初始化与销毁的回调方法这类似于xml配置文件中 bean元素中 init-method 与 destroy-method属性 【Bean注解定义】 package org.springframework.context.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; import org.springframework.core.annotation.AliasFor;Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface Bean {AliasFor(name)String[] value() default {};AliasFor(value)String[] name() default {};boolean autowireCandidate() default true;String initMethod() default ;String destroyMethod() default (inferred); } 【4.3.1】Bean注册的bean生命周期回调代码实践 【BeanAnnotationLifeCycleMain】 public class BeanAnnotationLifeCycleMain {public static void main(String[] args) {AnnotationConfigApplicationContext container new AnnotationConfigApplicationContext(BeanAnnotationLifeCycleConfig.class);// 注册了关闭钩子当容器销毁bean时才会调用 destory()方法container.registerShutdownHook();} }【执行效果】 BeanWithLifeCycleCallback init() BeanWithLifeCycleCallback destory()【BeanAnnotationLifeCycleConfig】 Bean注解指定bean初始时方法与销毁方法 Configuration public class BeanAnnotationLifeCycleConfig {Bean(initMethod init, destroyMethod destory)public BeanWithLifeCycleCallback beanWithInitMethod() {return new BeanWithLifeCycleCallback();} }【BeanWithLifeCycleCallback】带有生命周期回调的Bean public class BeanWithLifeCycleCallback {public void init() {System.out.println(BeanWithLifeCycleCallback init());}public void destory() {System.out.println(BeanWithLifeCycleCallback destory());}}【补充】上述注册生命周期初始化回调方法init等同于在构造器中执行init()方法 Configuration public class BeanAnnotationLifeCycleConfig2 {Beanpublic BeanWithLifeCycleCallback beanWithInitMethod() {BeanWithLifeCycleCallback beanWithLifeCycleCallback new BeanWithLifeCycleCallback();beanWithLifeCycleCallback.init(); // 类似与显式调用 init() 方法 return beanWithLifeCycleCallback;} }【提示】如果我们直接使用java配置容器我们可以直接对目标对象或bean执行任何操作而并不是总是依赖spring的生命周期回调 如BeanAnnotationLifeCycleConfig2那样 【4.4】指定bean作用范围 【4.4.1】使用Scope注解 1你可以指定使用Bean定义的bean的作用范围。你可以使用任何一种标准的作用范围。beans-factory-scopes 2默认scope作用范围是singleton-单例可以使用Scope注解重写scope 【ScopeOverwriteMain】重写bean的作用域main入口 public class ScopeOverwriteMain {public static void main(String[] args) {AnnotationConfigApplicationContext container new AnnotationConfigApplicationContext(ScopeOverrideConfig.class);// 获取 RepositoryA实例每次获取都会创建一个新实例因为其scope为prototypeSystem.out.println(container.getBean(RepositoryA.class));System.out.println(container.getBean(RepositoryA.class));// 获取 RepositoryB实例每次获取都会返回同一个实例因为其scope为singletonSystem.out.println(container.getBean(RepositoryB.class));System.out.println(container.getBean(RepositoryB.class));} // com.tom.chapter00.beanannotation.repository.RepositoryA59474f18 // com.tom.chapter00.beanannotation.repository.RepositoryA65fb9ffc // com.tom.chapter00.beanannotation.repository.RepositoryB3e694b3f // com.tom.chapter00.beanannotation.repository.RepositoryB3e694b3f }【ScopeOverrideConfig】 package com.tom.chapter00.beanannotation.scope.scopeoverride;import com.tom.chapter00.beanannotation.repository.RepositoryA; import com.tom.chapter00.beanannotation.repository.RepositoryB; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope;Configuration public class ScopeOverrideConfig {BeanScope(prototype) // 原型作用域每次获取bean都会创建1个新实例 public RepositoryA repositoryA() {return new RepositoryA();}BeanScope(singleton) // 单例作用域自始至终都只有1个实例 public RepositoryB repositoryB() {return new RepositoryB();} }【4.4.2】查找方法注入Lookup method injection仅了解本文不展开 1查找方法注入是你很少使用到的高级功能 查找方法注入在单例范围bean依赖原型范围bean场景下有用 public abstract class CommandManager {public Object process(Object commandState) {// grab a new instance of the appropriate Command interfaceCommand command createCommand();// set the state on the (hopefully brand new) Command instancecommand.setState(commandState);return command.execute();}// okay... but where is the implementation of this method?protected abstract Command createCommand(); }2使用java配置支持你可以创建CommandManager子类其抽象方法createCommand()被重写以便查找新的原型command对象 Bean Scope(prototype) public AsyncCommand asyncCommand() {AsyncCommand command new AsyncCommand();// inject dependencies here as requiredreturn command; }Bean public CommandManager commandManager() {// return new anonymous implementation of CommandManager with command() overridden// to return a new prototype Command objectreturn new CommandManager() {protected Command createCommand() {return asyncCommand();}} }解说CommandManager是单例的但其createCommand()方法返回的Command对象是原型的 【4.4.3】自定义bean的名称 1默认情况下Bean注解的方法名作为实例化bean的名称即bean名称repositoryA1参见下文的BeanNameConfig但若代码指定了Bean注解的name属性userRepo所以bean名称userRepo 2Bean注解的name属性接收一个string数组以便为一个bean指定多个别名 【BeanNameConfigMain】bean名称配置测试main public class BeanNameConfigMain {public static void main(String[] args) {AnnotationConfigApplicationContext container new AnnotationConfigApplicationContext(BeanNameConfig.class);System.out.println(container.getBean(repositoryA1));System.out.println(container.getBean(userRepo));System.out.println(container.getBean(userRepo1));System.out.println(container.getBean(userRepo2));System.out.println(container.getBean(userRepo3));} }【执行结果】 com.tom.chapter00.beanannotation.repository.RepositoryA692f203f com.tom.chapter00.beanannotation.repository.RepositoryA48f2bd5b com.tom.chapter00.beanannotation.repository.RepositoryA7b2bbc3 // 相同 com.tom.chapter00.beanannotation.repository.RepositoryA7b2bbc3// 相同 com.tom.chapter00.beanannotation.repository.RepositoryA7b2bbc3// 相同 【BeanNameConfig】 Configuration public class BeanNameConfig {Beanpublic RepositoryA repositoryA1() {return new RepositoryA();}Bean(userRepo) // 为bean指定1个别名 public RepositoryA repositoryA2() {return new RepositoryA();}Bean(name {userRepo1, userRepo2, userRepo3}) // 为bean指定3个别名public RepositoryA repositoryAWithMultipleName() {return new RepositoryA();} }【Bean注解源码】 Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface Bean {AliasFor(name)String[] value() default {};AliasFor(value)String[] name() default {};boolean autowireCandidate() default true;String initMethod() default ;String destroyMethod() default (inferred); }【5】所有Configuration类使用CGLIB进行子类化 1Bean标注的方法被调用2次会有什么效果 【BeanMoreInfoConfigMain】 public class BeanMoreInfoConfigMain {public static void main(String[] args) {AnnotationConfigApplicationContext container new AnnotationConfigApplicationContext(BeanMoreInfoConfig.class);System.out.println(container.getBean(userService1, UserService.class).getUserRepository());System.out.println(container.getBean(userService2, UserService.class).getUserRepository());} }【打印效果】 调用2次userRepository() 获取的是同一个UserRepository bean 为什么 ; // com.tom.chapter00.config.importannotation.injectdependency.UserRepository4c583ecf // com.tom.chapter00.config.importannotation.injectdependency.UserRepository4c583ecf【BeanMoreInfoConfig】 Configuration public class BeanMoreInfoConfig {Beanpublic UserService userService1() {return new UserService(userRepository()); // 第1次调用userRepository()}Beanpublic UserService userService2() {return new UserService(userRepository()); // 第2次调用userRepository()}Beanpublic UserRepository userRepository() {return new UserRepository();} }【5.1】java配置类内部运行原理重要 1由上述可知调用2次userRepository() 获取的是同一个UserRepository bean 原理解说所有 Configuration类在启动时使用CGLIB子类化。 简单理解是 Configuration类作为父类CGLIB通过字节码增强产生一个子类 在获取bean时首先子类中子方法会校验缓存中是否存在该bean若有则直接返回否则再调用父方法并创建新实例 2本例的注意点 本例演示的场景是基于单例bean若bean范围不是单例则运行原理不同注意到为了让java配置的容器可以正常运行你必须在依赖清单中包含CGLIB jar由于CGLIB在启动时动态增强了一些功能所以有一些限制条件 Configuration类不应该是final否则不能被继承Configuration类应该有一个无参构造器
http://www.dnsts.com.cn/news/180980.html

相关文章:

  • 门户网站网站开发产品推广方案范文500字
  • 楼梯 技术支持 东莞网站建设提高网站权重的作用
  • 好的淘客网站wordpress怎么发布文章带图片
  • 打开网站显示建设中微信小程序怎么做会员系统
  • 温岭 网站制作php一个企业网站多钱
  • 了解网站建设邵东做网站
  • 石家庄哪里有网站建设华东民航机场建设公司网站
  • 网站备案有效期湖南企业网站建设制作
  • dw做网站 怎么做背景图片如何做旅游网站推销
  • 如何将网站加入百度图 推广新网站建设的流程
  • 怎样做网页游戏网站网站上传空间下一步
  • 网站开发实训小结做网站销售门窗怎么做
  • 电脑网站建设在哪里建设一个网站可以做什么
  • wordpress开发视频网站wordpress多媒体路径
  • 长春网站制作套餐视频播放网站开发的报告
  • 网站开发 程序开发阶段小程序定制开发话术
  • 网站禁止访问怎么解除安卓应用软件开发方向
  • 做一个网站需要怎么做怎做卖东西的网站
  • 免费企业网站cms系统微信推广文案范文
  • 深圳网站优化培训广州建网站开发seo型企业网站
  • 手机网站建设推广最新wordpress模板
  • 微能力者恶魔网站谁做的网站设置在设备之间共享什么意思
  • 公司网站建站流程做胎压的网站
  • html网页设计环保网站宠物网站建设规划书
  • python能否做网站网站要流量有什么用
  • 绵阳网站关键词搜网站内容
  • 市住房城乡建设网站企业型网站价目表
  • 中国数据网站空间广州越秀区是不是中风险地区
  • 住房和城乡建设部网站如何让自己做的博客网站上线
  • 上海建设银行网站查询余额那个网站可以做考卷