栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java 培训如何用反射做简易 Spring IOC 容器

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java 培训如何用反射做简易 Spring IOC 容器

前言

在学习 Spring 之后,对其中的工作原理产生了浓厚的兴趣,近些日子看视频了解到了一些 SpringIOC 容器的工作原理,并边打边磨做出了一个非常简易的 SpringIOC 容器,实现了他的 XML 文件装配,java 代码装配以及自动装配的功能,下面思路以及代码

一、模仿 XML 形式的装配思路

1.思路

采用 XML 装配 bean 时 Spring 会解析 applicationContext.xml 文件,并将各种类型的 bean 注入 IOC 容器,容器中的 bean 可以被无数次重复调用,极大地提高了系统效率而不用多次重复的 new 对象。

为了模仿 IOC,我们利用 Map 集合存放需要的 bean,并新建一个 conf.properties 文件存放信息,存放 com.wql.dao.userDao=com.wql.daoImpl.userDaoImpl 等数据信息_java培训

在获取 bean 之前解析 conf.properties 文件中的信息,利用反射技术将 conf.properties 文件中的内容通过 Class.forName 的形式解析为 Class 对象放入集合 map 中,这样每次获取对象都会从 map 中进行获取,不必再 new

2.具体代码实现

conf.properties:

com.wql.dao.userDao=com.wql.daoImpl.userDaoImpl

com.wql.service.userService=com.wql.serviceImpl.userServiceImpl

MyApplicationContext 类代码实现:

package com.wql.application;

import java.io.InputStream;

import java.util.HashMap;

import java.util.Map;

import java.util.Properties;

import java.util.Set;

public class MyApplicationContext {

//模拟 IOC 容器

private Map map = new HashMap<>();

private String ResourcePath;

private String filepath;

public MyApplicationContext() {

}

public MyApplicationContext(String resourcePath) {

ResourcePath = resourcePath;

}

//获得一个类型不知的对象(通过 map 集合)

public T getBean(Class clazz){

return (T)map.get(clazz);

}

//通过 properties 中存储的键值对获取 Class 对象,并注入进 map 集合

public void initXMLSpringIOC(){

try{

InputStream stream = MyApplicationContext.class.getClassLoader().getResourceAsStream(ResourcePath);

Properties properties = new Properties();

properties.load(stream);

//获取内容

Set keys = properties.keySet();

for(Object key:keys){

//Class:实例

map.put(Class.forName(key.toString()),Class.forName(properties.getProperty(key.toString())).newInstance() );

}

}catch (Exception e){

e.printStackTrace();

}

}

} 

我们对代码进行测试:

可见成功获得对象

但是通过此种方式进行装配的方式似乎已经过时了,下面我们通过 @Bean 实现注入

二、通过注解方式进行注入

1.思路

 

 

先获取项目路径,然后通过字符串截取的方式获取接口实现类的全路径,通过反射技术检查该类是否含有 @Bean 注解,有则加入 map

2.代码实现

@Bean:

package com.wql.Annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Bean {

}

MyApplicationContext 类代码实现:

//通过注解进行 bean 的装配

public void initAnnotationSpringIOC(){

filepath = MyApplicationContext.class.getClassLoader().getResource("").getFile();

//获取项目路径后

System.out.println(filepath);

loadOne(new File(filepath));

}

private void loadOne(File fileparent) {

if(fileparent.isDirectory()){

//获取子文件

File[] files = fileparent.listFiles();

if(files.length==0||files==null){

return;

}else{

//其下文件夹不为空

for(File file:files){

if(file.isDirectory()){

loadOne(file);

}else{

try{

String oldpath = file.getAbsolutePath().substring(filepath.length()-1,file.getAbsolutePath().length());

if(oldpath.contains(".class")){

String newpath = oldpath.replaceAll("\\",".").replace(".class","");

Class aClass = Class.forName(newpath);

//模拟装配 bean

if(!aClass.isInterface()){

if(aClass.getAnnotation(Bean.class)!=null){

//证明此类包含 Bean 注解,将其加入 map

map.put(aClass.getInterfaces()[0],aClass.newInstance());

}

}

}

}catch (Exception e){

e.printStackTrace();

}

}

}

}

}

}

在代码中我们步步逼近,通过 MyApplicationContext.class.getClassLoader().getResource("").getFile();获取项目路径,这样我们就有了获取

项目路径:

/D:/IdeaJava/untitled1/out/production/MySpringIOCProject/

利用 file.getAbsolutePath().substring(filepath.length()-1,file.getAbsolutePath().length()); 我们成功截取到.class 文件和其他文件的路径

comwqlAnnotationBean.class

comwqlAnnotationMyAutowired.class

comwqlapplicationApplicationContext.class

comwqlapplicationMyApplicationContext.class

comwqldaouserDao.class

comwqldaoImpluserDaoImpl.class

comwqlentityUser.class

comwqlserviceuserService.class

comwqlserviceImpluserServiceImpl.class

comwqltesttest.class

conf.properties

meta-INFMySpringIOCProject.kotlin_module

然后利用 contains 方法过滤出后缀名为.class 的文件,对其路径进行更改将/用.进行替换,将.class 字符删除

我们得到:

com.wql.Annotation.Bean

com.wql.Annotation.MyAutowired

com.wql.application.ApplicationContext

com.wql.application.MyApplicationContext

com.wql.dao.userDao

com.wql.daoImpl.userDaoImpl

com.wql.entity.User

com.wql.service.userService

com.wql.serviceImpl.userServiceImpl

com.wql.test.test

此时我们离成功已经很近了,我们利用上一步获取的全类名,使用 Class.forName 获取 Class 对象,利用 aClass.isInterface()与 aClass.getAnnotation(Bean.class)我么你判断其实否为接口与是否含有 @Bean 注解,不为接口且含有 @Bean 注解,我们获得它的实例并将其加入 map 中

com.wql.daoImpl.userDaoImpl

com.wql.serviceImpl.userServiceImpl

测试:

userDaoImpl:

package com.wql.daoImpl;

import com.wql.Annotation.Bean;

import com.wql.dao.userDao;

@Bean

public class userDaoImpl implements userDao {

@Override

public void test() {

System.out.println("成功自动装配");

}

}

成功通过 @Bean 进行注入

三、@Autowired 自动装配

自动装配要先有东西才能装呀,所以我们只能先遍历 map 集合,获取已经存在 map 中的对象的 Class,再获取他们的字段,判断字段上是否含有 @Autowired 注解,有的话进行自动装配即可

代码:

MyAutowired:

package com.wql.Annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAutowired {

}

userDaoImpl 类代码实现:

package com.wql.daoImpl;

import com.wql.Annotation.Bean;

import com.wql.dao.userDao;

@Bean

public class userDaoImpl implements userDao {

@Override

public void test() {

System.out.println("成功自动装配");

}

}

serviceImpl:

package com.wql.serviceImpl;

import com.wql.Annotation.MyAutowired;

import com.wql.Annotation.Bean;

import com.wql.dao.userDao;

import com.wql.service.userService;

@Bean

public class userServiceImpl implements userService {

@MyAutowired

public userDao userDao;

@Override

public void test() {

userDao.test();

}

}

MyApplicationContext 类代码实现:

//通过注解进行 bean 的装配

public void initAnnotationSpringIOC(){

filepath = MyApplicationContext.class.getClassLoader().getResource("").getFile();

//获取项目路径后

System.out.println(filepath);

loadOne(new File(filepath));

AnnotationAutowired();

}

//自动装配

private void AnnotationAutowired() {

for(Map.Entry entry:map.entrySet()){

Object obj = entry.getValue();

Class aClass = obj.getClass();

Field[] fields = aClass.getDeclaredFields();

for(Field field: fields){

field.setAccessible(true);

if(field.getAnnotation(MyAutowired.class)!=null){

try{

field.set(obj,map.get(field.getType()));

}catch (Exception e){

e.printStackTrace();

}

}

}

}

}

 测试:

自动装配测试成功

总结

小伙伴们有兴趣想了解更多相关学习资料请点赞收藏+评论转发+关注我之后
私信我,注意回复【000】即可获取更多免费资料!

最后附上 MyApplicationContext 的全部代码:

package com.wql.application;

import com.wql.Annotation.Bean;

import com.wql.Annotation.MyAutowired;

import java.io.File;

import java.io.InputStream;

import java.lang.reflect.Field;

import java.util.HashMap;

import java.util.Map;

import java.util.Properties;

import java.util.Set;

public class MyApplicationContext {

//模拟 IOC 容器

private Map map = new HashMap<>();

private String ResourcePath;

private String filepath;

public MyApplicationContext() {

}

public MyApplicationContext(String resourcePath) {

ResourcePath = resourcePath;

}

//获得一个类型不知的对象(通过 map 集合)

public T getBean(Class clazz){

return (T)map.get(clazz);

}

//通过 properties 中存储的键值对获取 Class 对象,并注入进 map 集合

public void initXMLSpringIOC(){

try{

InputStream stream = MyApplicationContext.class.getClassLoader().getResourceAsStream(ResourcePath);

Properties properties = new Properties();

properties.load(stream);

//获取内容

Set keys = properties.keySet();

for(Object key:keys){

//Class:实例

map.put(Class.forName(key.toString()),Class.forName(properties.getProperty(key.toString())).newInstance() );

}

}catch (Exception e){

e.printStackTrace();

}

}

//通过注解进行 bean 的装配

public void initAnnotationSpringIOC(){

filepath = MyApplicationContext.class.getClassLoader().getResource("").getFile();

//获取项目路径后

System.out.println(filepath);

loadOne(new File(filepath));

AnnotationAutowired();

}

private void loadOne(File fileparent) {

if(fileparent.isDirectory()){

//获取子文件

File[] files = fileparent.listFiles();

if(files.length==0||files==null){

return;

}else{

//其下文件夹不为空

for(File file:files){

if(file.isDirectory()){

loadOne(file);

}else{

try{

String oldpath = file.getAbsolutePath().substring(filepath.length()-1,file.getAbsolutePath().length());

if(oldpath.contains(".class")){

String newpath = oldpath.replaceAll("\\",".").replace(".class","");

Class aClass = Class.forName(newpath);

//模拟装配 bean

if(!aClass.isInterface()){

if(aClass.getAnnotation(Bean.class)!=null){

//证明此类包含 Bean 注解,将其加入 map

map.put(aClass.getInterfaces()[0],aClass.newInstance());

}

}

}

}catch (Exception e){

e.printStackTrace();

}

}

}

}

}

}

//自动装配

private void AnnotationAutowired() {

for(Map.Entry entry:map.entrySet()){

Object obj = entry.getValue();

Class aClass = obj.getClass();

Field[] fields = aClass.getDeclaredFields();

for(Field field: fields){

field.setAccessible(true);

if(field.getAnnotation(MyAutowired.class)!=null){

try{

field.set(obj,map.get(field.getType()));

}catch (Exception e){

e.printStackTrace();

}

}

}

}

}

} 

 

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号