今天照着网络上的资源学习spring入门项目,用ClassPathXmlApplicationContext获得了一个HelloWorld对象,按照惯例输出了一句"HelloWorld",代码大家应该都写过:
//1.bean配置文件位置
String beanXml = "classpath:resource/beans.xml";
//2.创建ClassPathXmlApplicationContext容器,给容器指定需要加载的bean配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
//3.从容器中获取需要的bean
HelloWorld helloWorld = context.getBean("helloWorld", HelloWorld.class);
//4.调用方法
helloWorld.show();
看着输出结果的我突然有了两个疑问:
1.对象是怎么得到的?
2.为什么调用getBean得到的对象不需要强转?(想获得HelloWorld 对象就能用HelloWorld 来接,而不是HelloWorld h = (HelloWorld)context.getBean(xxxxxxx) )
老师说过要带着问题进行学习,既然现在问题已经有了那就开始学习吧。
首先是怎么获得HelloWorld对象的问题:
之前翻大佬们的博客时就get到了一个点,框架的灵魂所在就是反射,而getBean(Bean的id,Beand的字节码)正好也要求传入HelloWorld的字节码文件,所以这里我用反射粗糙地进行了一个模拟,写了一个简单的getBean方法,概念1.0代码如下:
//测试用例
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
HelloWorld helloWorld2 = getBean(HelloWorld.class);
helloWorld2.show();
}
/**
* 概念1.0
*/
public static HelloWorld getBean(Class<HelloWorld> typeClass)
throws InstantiationException, IllegalAccessException {
HelloWorld helloWorld = null;
// 根据字节码获得对象
helloWorld = typeClass.newInstance();
return helloWorld;
}
}
输出结果:
Hello World!!!
不考虑解析beans.xml、注入容器等步骤,这个传入的Class对象最终可以让我们在调用getBean之后返回一个HelloWorld对象,但是spring是不可能只控制反转HelloWorld这一个类的,而且总不能直接动spring源码,所以我进一步的考虑就是
如何通过反射来根据传进的Class字节码返回各种各样的对象?
我的解决办法是把参数的Class的参数类型去掉,只返回一个Object,再让调用的地方进行类型转换, 概念2.0代码如下:
//测试用例
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//获得HelloWorld对象
HelloWorld helloWorld2 = (HelloWorld)getBean(HelloWorld.class);
//使用HelloWorld对象
helloWorld2.show();
//调用Student对象
Student student = (Student)getBean(Student.class);
//使用Student对象
student.show();
}
/**
* 概念2.0
*/
public static Object getBean(Class typeClass) throws InstantiationException, IllegalAccessException {
Object obj = null;
// 根据字节码获得对象
obj = typeClass.newInstance();
return obj;
}
}
输出结果:
Hello World!!!
这是个学生!!!
到这里我就可以获得各式各样的对象了,但是总觉得哪里怪怪的,我每一次想获得一个对象X,不但要把X.class传进去,拿出来还要再做个强转?这也太麻烦了吧!这个时候我又开始想第二个问题:
为什么spring不需要我的概念2.0一样的强转?点进getBean第一层源码,立马看到了T这个字母
原来这块我应该总结一下spring的思想了,如果我们传A,获取A,那就相当于传参T,return个T,这种情况用 泛型是很可行的,也能减少调用者的无用代码(强转),赶紧修改出了今天最后的 概念3.0,代码如下:
//测试用例
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
HelloWorld helloWorld2 = getBean(HelloWorld.class);
helloWorld2.show();
Student student = getBean(Student.class);
student.show();
}
/**
* 概念3.0
*/
public static <T> T getBean(Class<T> typeClass) throws InstantiationException, IllegalAccessException {
T obj = null;
// 根据字节码获得对象
obj = typeClass.newInstance();
return obj;
}
}
输出:
Hello World!!!
这是个学生!!!
小记
之前学过泛型,但是除了学习阶段的Demo之外没有正儿八经的利用过他。之前看大佬们的博客经常会被教导“spring会简化开发,但我们应该学习spring内部各位大神的写法与思维”。今天就发现让我来简化大家的开发的话我的大体思维就只能想到2.0,但是spring最简单的地方都是概念3.0的级别,这才是需要学习的精华呀。以后的spring学习之路上,我一定不会觉得打个注解导个jar包就是会了,虚心学习,天天向上。