模拟spring IoC基于注解底层解耦过程
在xml中开启包扫描,spring就会去扫描指定包下面的组件
通过反射机制去过滤组件上是否有spring提供的注解(Controller、service)
如果有注解,spring会通过反射机制创建实例保存到容器中
然后spring会根据反射机制检测该类中是否有属性需要注入(也就是属性上是否有spring提供的注解)
如果有注解,spring会根据反射机制进行注入
反射+设计模式+注解(自定义)
Dao
package com.guoy.spring.ioc.account.dao;
public interface AccountDao {
void saveAccount();
}
package com.guoy.spring.ioc.account.dao;
import com.guoy.spring.ioc.annotation.Repository;
@Repository
public class AccountDaoImpl implements AccountDao {
@Override
public void saveAccount() {
System.out.println("成功保存了账户");
}
}
Service
package com.guoy.spring.ioc.account.service;
public interface AccountService {
void saveAccount();
}
package com.guoy.spring.ioc.account.service;
import com.guoy.spring.ioc.account.dao.AccountDao;
import com.guoy.spring.ioc.annotation.Autowired;
import com.guoy.spring.ioc.annotation.Service;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
Servlet
package com.guoy.spring.ioc.account.servlet;
import com.guoy.spring.ioc.account.service.AccountService;
import com.guoy.spring.ioc.annotation.Autowired;
import com.guoy.spring.ioc.annotation.Controller;
@Controller
public class AccountServlet {
@Autowired
private AccountService accountService;
public void saveAccount(){
accountService.saveAccount();
}
}
Annotation
- 自定义注解Autowired
package com.guoy.spring.ioc.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 Autowired {
}
- 自定义注解Controller
package com.guoy.spring.ioc.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 Controller {
}
- 自定义持久层注解Repository
package com.guoy.spring.ioc.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 Repository {
}
- 自定义业务层注解Service
package com.guoy.spring.ioc.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 Service {}
BeanFactory
package com.guoy.spring.ioc.factory;
import java.util.HashMap;
import java.util.Map;
/**
* 工厂对象,用于存放组件的实例
*/
public class BeanFactory {
private static Map<String,Object> beanMap = new HashMap<>();
public static Map<String, Object> getBeanMap() {
return beanMap;
}
public static void setBeanMap(Map<String, Object> beanMap) {
BeanFactory.beanMap = beanMap;
}
/**
* //用户用于获取实例的方法
* @return
*/
public static Object getBean(String beanId){
Object obj = beanMap.get(beanId);
return obj;
}
}
ComponentScan
package com.guoy.spring.ioc.scan;
import com.guoy.spring.ioc.annotation.Autowired;
import com.guoy.spring.ioc.annotation.Controller;
import com.guoy.spring.ioc.annotation.Repository;
import com.guoy.spring.ioc.annotation.Service;
import com.guoy.spring.ioc.factory.BeanFactory;
import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 模拟spring底层基于注解的ioc解耦
*
* @author ShuaiGUO
*/
public class ComponentScan {
//声明一个集合,用于保存全类名
private static List<String> fileList = new ArrayList<>();
/**
* 模拟装配实例、注入实例的整个过程
* pathName 扫描的包
*/
public static void getCompoentScan(String pathName){
pathName = pathName.replace(".","/");
//获取当前工程的绝对路径
String path = ClassLoader.getSystemResource("").getPath()+pathName;
//创建file对象,file对象可以表示一个文件夹、或者是一个文件、或者是文件所对应的目录
File file = new File(path);
//调用递归方法,用于所有的文件夹过滤
addFiles(file);
//遍历集合
for (String className : fileList) {
try {
//创建字节码对象
Class aClass = Class.forName(className);
//根据反射机制检测类上有没有自定义注解
Controller controller = (Controller)aClass.getAnnotation(Controller.class);
Service service = (Service)aClass.getAnnotation(Service.class);
Repository repository = (Repository)aClass.getAnnotation(Repository.class);
//判断是否三个注解中任意注解不为空,将实例添加到工厂
if (controller !=null || service != null || repository != null){
//根据反射创建实例对象
Object obj = aClass.newInstance();
//获取类的简类名
String simpleName = aClass.getSimpleName();
//添加实例到工厂
BeanFactory.getBeanMap().put(simpleName,obj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//再次遍历集合,将需要注入的属性进行注入
for (String className : fileList) {
try {
//创建字节码对象
Class aClass = Class.forName(className);
//根据反射机制检测类上有没有自定义注解
Controller controller = (Controller)aClass.getAnnotation(Controller.class);
Service service = (Service)aClass.getAnnotation(Service.class);
Repository repository = (Repository)aClass.getAnnotation(Repository.class);
//如果类上有其中一个注解,就把该类实例添加到容器中
if (controller != null || service != null || repository != null){
//根据反射获取类中的属性
Field[] declaredFields = aClass.getDeclaredFields();
//遍历属性数组
for (Field declaredField : declaredFields) {
//检测属性上是否有自定义的注解(Autowired)
Autowired autowired = declaredField.getAnnotation(Autowired.class);
//如果这个注解不为空,那就意味着这个属性需要被注入
if (autowired != null){
//获取map集合
Map<String, Object> beanMap = BeanFactory.getBeanMap();
//将map集合转成set集合
Set<Map.Entry<String, Object>> entries = beanMap.entrySet();
//遍历map集合
for (Map.Entry<String, Object> entry : entries) {
//因为我们聚合的实例是接口,获取接口集合
Class[] interfaces = entry.getValue().getClass().getInterfaces();
//遍历集合
for (Class anInterface : interfaces) {
//接口与属性名相同
if (anInterface == declaredField.getType()){
//打破封装,因为是private
declaredField.setAccessible(true);
//给属性赋值
declaredField.set(BeanFactory.getBean(aClass.getSimpleName()),entry.getValue());
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 定义一个递归的方法
* file.listFiles() 将所有文件或者文件夹切成一个数组
* FileFilter接口, 用于文件过滤的接口,可以将文件夹过滤掉
*/
public static void addFiles(File file){
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
//isDirectory()判断当前文件是否是文件夹
if (pathname.isDirectory()){
//继续调用递归方法
addFiles(pathname);
}
//获取符合要求的文件,应该是.class结尾的文件
return pathname.getPath().endsWith(".class");
}
});
//遍历文件数组,将符合要求的文件路径切割成全类名
for (File f : files) {
String path = f.getPath();
//System.out.println(path);//E:\dev\spring_Ioc\out\production\spring_Ioc\com\guoy\spring\ioc\scan\CompoentScan.class
//将斜杠替(\)换成点(.)
path = path.replace("\\",".");
//System.out.println(path);//E:.dev.spring_Ioc.out.production.spring_Ioc.com.guoy.spring.ioc.scan.CompoentScan.class
//将com包前面的字符串删掉
path = path.substring(path.lastIndexOf("com"),path.length());
//System.out.println(path);//com.guoy.spring.ioc.scan.CompoentScan.class
//将.class删除
path = path.replace(".class","");
//System.out.println(path);//com.guoy.spring.ioc.scan.CompoentScan
//将符合要求的全类名放入集合
fileList.add(path);
}
}
}
Test
package com.guoy.spring.ioc.scan;
import com.guoy.spring.ioc.account.servlet.AccountServlet;
import com.guoy.spring.ioc.factory.BeanFactory;
public class Test {
public static void main(String[] args) {
//开启扫描包
ComponentScan.getCompoentScan("com.guoy");
//从工厂获取实例
AccountServlet accountServlet =(AccountServlet) BeanFactory.getBean("AccountServlet");
//调用保存账户的方法
accountServlet.saveAccount();
}
}
结果:
成功保存了账户