// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
项目基本结构

//定义扫描路劲
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
}
//配置类
@ComponentScan("com.test.service")
public class AppConfig {
}
@Component("userService")
@Scope("prototype")
public class UserService {
public void test(){
System.out.println("useService");
}
}
public class OrderService {
public void test(){
System.out.println("orderService");
}
}
public class TestApplicationContext {
private Class configClass;
//存储BeanDefinition对象
private Map<String,BeanDefinition> beanDefinitionMap=new HashMap<>();
//单例池map,存储单例bean对象
Map<String,Object> singletonObject=new HashMap<>();
public TestApplicationContext(Class configClass) {
this.configClass = configClass;
}
public Object getBean(String name){
return null;
}
}
public class Test {
public static void main(String[] args) {
//创建conext容器,创建单例bean,Appconfig构造方法中完成
TestApplicationContext applicationContext = new TestApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("UserService");
}
}
至此大体框架已经完成,接下来完成如何扫描,创建bean对象,bean初始化前,初始化,初始化后的相关实现等等
public TestApplicationContext(Class configClass) {
this.configClass = configClass;
//扫描
scan(configClass);
}
private void scan(Class configClass) {
//判断当前类上是否有ComponentScan注解
if (configClass.isAnnotationPresent(ComponentScan.class)){
ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
String path = componentScanAnnotation.value();
path=path.replace(".","/"); // com/test/service
//获取target包下的class文件取出,解析注解,通过Appclassloader类加载器获取
ClassLoader classLoader = TestApplicationContext.class.getClassLoader();
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
//取出目录下的文件,遍历
if (file.isDirectory()){
for (File f : file.listFiles()) {
String absolutePath = f.getAbsolutePath();
//path(C:\Users\cchuang4\IdeaProjects\springDemo\target\classes\com\test\service\OrderService.class)转换成com.test.service
absolutePath=absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
absolutePath=absolutePath.replace("\\",".");
try {
//判断class文件是否有@Component注解
//将class文件加载进来成为class对象
Class<?> clazz = classLoader.loadClass(absolutePath);
if (clazz.isAnnotationPresent(Component.class)){
//获取beanname
Component componentAnnotation = clazz.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
//创建BeanDefinition对象
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(clazz);
//Bean是否为单例或原型
if (clazz.isAnnotationPresent(Scope.class)){
Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
String value = scopeAnnotation.value();
beanDefinition.setScope(value);
}else {
//单例
beanDefinition.setScope("singleton");
}
//将bean的相关元信息存入beandefinitionMap
beanDefinitionMap.put(beanName,beanDefinition);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}
}
创建BeanDefinfition
package com.spring;
public class BeanDefinition {
//类型
private Class type;
//作用域
private String scope;
//是否懒加载
private boolean isLazy;
public Class getType() {
return type;
}
public void setType(Class type) {
this.type = type;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public boolean isLazy() {
return isLazy;
}
public void setLazy(boolean lazy) {
isLazy = lazy;
}
}
public TestApplicationContext(Class configClass) {
this.configClass = configClass;
//扫描
scan(configClass);
//遍历map
for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
String beanName= entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if (beanDefinition.getScope().equals("singleton")){
//获取单例bean
Object bean = createBean(beanName, beanDefinition);
//将单例bean存进单例池的map中,在getBean()时直接拿取
singletonObject.put(beanName,bean);
}
}
}
public Object getBean(String beanName){
//判断是否有这个bean
if (!beanDefinitionMap.containsKey(beanName)){
throw new NullPointerException();
}else {
//获取beanDefinition对象
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//判断单例/原型bean
if (beanDefinition.getScope().equals("singleton")){
//从单例池中直接获取
Object singletonBean = singletonObject.get(beanName);
return singletonBean;
}else {
//原型
Object prototypeBean = createBean(beanName, beanDefinition);
return prototypeBean;
}
}
}
createBean()方法,创建bean对象
Object createBean(String beanName,BeanDefinition beanDefinition){
Class clazz = beanDefinition.getType();
Object instance = null;
try {
instance = clazz.getConstructor().newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
return instance;
}
至此已经支持单例bean和原型bean的获取。
!!!测试运行Test类
1.当userService的@Scope("singleton")时:

1.当userService的@Scope("prototype")时:

此时@Component注解上要指定beanName,否则会NPE,如何获取默认的bean的名字?
//设置默认beanName
if (beanName.equals("")){
beanName= Introspector.decapitalize(clazz.getSimpleName());
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
String value() default "";
}
UserService.class
@Component("userService")
@Scope("prototype")
public class UserService {
@Autowired
private OrderService orderService;
public void test(){
System.out.println(orderService);
}
}
Object createBean(String beanName,BeanDefinition beanDefinition){
Class clazz = beanDefinition.getType();
Object instance = null;
try {
instance = clazz.getConstructor().newInstance();
//依赖注入
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)){
field.setAccessible(true);
//根据type去单例池或beanDefinitionMap中去找
//...省略
//根据beanName去找
field.set(instance,getBean(beanName));
}
}
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
return instance;
}
public Object getBean(String beanName){
//判断是否有这个bean
if (!beanDefinitionMap.containsKey(beanName)){
throw new NullPointerException();
}else {
//获取beanDefinition对象
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//判断单例/原型bean
if (beanDefinition.getScope().equals("singleton")){
//从单例池中直接获取
Object singletonBean = singletonObject.get(beanName);
//若此时对应的bean还没有创建,如在依赖注入时
if (singletonBean==null){
singletonBean=createBean(beanName,beanDefinition);
singletonObject.put(beanName,singletonBean);
}
return singletonBean;
}else {
//原型
Object prototypeBean = createBean(beanName, beanDefinition);
return prototypeBean;
}
}
}
测试,输出UserService里的OrderService对象:

此时依赖注入已经完成
public interface InitializingBean{
void afterPropertiesSet() throws Exception;
}
UserService.class
@Component("userService")
@Scope("prototype")
public class UserService implements InitializingBean {
@Autowired
private OrderService orderService;
public void test(){
System.out.println(orderService);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
}
此时在UserService加载时afterPropertiesSet不能自动调到。
//调用实现了InitializingBean的afterPropertiesSet方法
if (instance instanceof InitializingBean){
((InitializingBean)instance).afterPropertiesSet();
}
该接口也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。
创建BeanPostProcessor接口
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName){
return bean;
}
default Object postProcessAfterInitialization(Object bean, String beanName){
return bean;
}
}
此时的bean的后置处理器会针对所有bean,若想针对其中一个bean,则需自己写处理逻辑。
@Component
public class TestBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println(beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
//存放BeanPostProcessor对象
List<BeanPostProcessor> beanPostProcessorList=new ArrayList<>();
if (clazz.isAnnotationPresent(Component.class)){
//判断类是否实现了BeanPostProcessor接口
if (BeanPostProcessor.class.isAssignableFrom(clazz)){
//获得BeanPostProcessor的实例
BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
//将BeanPostProcessor对象存入list(LinkList)
beanPostProcessorList.add(instance);
}
......
//调用初始化后方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
}
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.
转自:spring.profiles.active和spring.profiles.include的使用及区别说明下文笔者讲述spring.profiles.active和spring.profiles.include的区别简介说明,如下所示我们都知道,在日常开发中,开发|测试|生产环境都拥有不同的配置信息如:jdbc地址、ip、端口等此时为了避免每次都修改全部信息,我们则可以采用以上的属性处理此类异常spring.profiles.active属性例:配置文件,可使用以下方式定义application-${profile}.properties开发环境配置文件:application-dev
假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定
我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho
我有一个rspec模拟对象,一个值赋给了属性。我正在努力在我的rspec测试中满足这种期望。只是想知道语法是什么?代码:defcreate@new_campaign=AdCampaign.new(params[:new_campaign])@new_campaign.creationDate="#{Time.now.year}/#{Time.now.mon}/#{Time.now.day}"if@new_campaign.saveflash[:status]="Success"elseflash[:status]="Failed"endend测试it"shouldabletocreat
我无法运行Spring。这是错误日志。myid-no-MacBook-Pro:myid$spring/Users/myid/.rbenv/versions/1.9.3-p484/lib/ruby/gems/1.9.1/gems/spring-0.0.10/lib/spring/sid.rb:17:in`fiddle_func':uninitializedconstantSpring::SID::DL(NameError)from/Users/myid/.rbenv/versions/1.9.3-p484/lib/ruby/gems/1.9.1/gems/spring-0.0.10/li
我正在尝试测试命令行工具的输出。如何使用rspec来“伪造”命令行调用?执行以下操作不起作用:it"shouldcallthecommandlineandreturn'text'"do@p=Pig.new@p.should_receive(:run).with('my_command_line_tool_call').and_return('resulttext')end如何创建stub? 最佳答案 使用newmessageexpectationsyntax:规范/虚拟规范.rbrequire"dummy"describeDummy
目录SpringBootStarter是什么?以前传统的做法使用SpringBootStarter之后starter的理念:starter的实现: 创建SpringBootStarter步骤在idea新建一个starter项目、直接执行下一步即可生成项目。 在xml中加入如下配置文件:创建proterties类来保存配置信息创建业务类:创建AutoConfiguration测试如下:SpringBootStarter是什么? SpringBootStarter是在SpringBoot组件中被提出来的一种概念、简化了很多烦琐的配置、通过引入各种SpringBootStarter包可以快速搭建出一