一.需要的maven依赖
<!--cglib动态代理--> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>3.3.0</version> </dependency> <!--包扫描工具,用于寻找注解--> <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.11</version> </dependency>
二.ioc及cglib实现代码
1.autowired注解,用于成员变量属性注入
package com.xy.ioc;
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 {
/**
* 当前注入对象的类型
*/
Class <?> classes ();
}
classes为当前要注入的实现类,这么写流程更简单,不用进行复杂的逻辑判断,也不会出现依赖注入失败的问题
如:
@AutoWired(classes = UserServiceImpl.class) private UserService userServiceImpl;
2.component注解,指定类存入bean管理容器中
package com.xy.ioc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标有该注解的类会在IoC容器中产生相对应的对象
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
}
3.packageScan注解,扫描指定包目录,用于反射bean对象
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解扫描
* 扫描value中的包下的所有注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PackageScan {
String value() default "";
}
4.bean管理容器,用于存储反射生成的bean代理对象
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* IoC容器
*/
public class ApplicationContext {
/**
* 装有 [类名 : 类对应的实例] 的容器
*/
private Map<String, Object> objectMap;
/**
* 初始化map
*/
protected ApplicationContext() {
this.objectMap = new ConcurrentHashMap<>();
}
/**
* 添加类,并创建相应的实例对象到map容器中
*
* @param clazz 所添加的类对象
*/
protected <T> void push(Class<T> clazz) {
try {
//创建动态代理类
T proxy = CglibProxyFactory.getProxy(clazz);
if(proxy!=null){
//将代理类存入map容器中
this.objectMap.put(clazz.getSimpleName(), proxy);
}else{
this.objectMap.put(clazz.getSimpleName(), clazz.newInstance());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取类所继承的接口
*
* @param clazz 通过类实例反射来所获取类所继承的的接口
* @return 所获取的类所继承的接口
*/
public <T> T getObject(Class<T> clazz) {
return (T) this.getObjectMap().get(clazz.getSimpleName());
}
/**
* 获取map容器键的集合
*
* @return 获取所有键值对
*/
protected Set<String> classSet() {
return this.objectMap.keySet();
}
public Map<String, Object> getObjectMap() {
return this.objectMap;
}
/**
* 单例模式
*/
private static ApplicationContext instance;
public static ApplicationContext getInstance() {
if (instance == null) {
instance = new ApplicationContext();
}
return instance;
}
}
5.ioc功能实现
package com.xy.ioc.implement;
import com.xy.exception.AttributeInjectionException;
import com.xy.exception.HasNoBeanException;
import com.xy.ioc.AutoWired;
import com.xy.ioc.Component;
import com.xy.ioc.PackageScan;
import org.reflections.Reflections;
import java.lang.reflect.Field;
import java.util.Set;
/**
* IOC 功能实现
*/
public class MyApplication {
private static MyApplication application;
protected ApplicationContext applicationContext;
/**
* 初始化bean容器
*/
public MyApplication() {
this.applicationContext = ApplicationContext.getInstance();
}
/**
* 通过run方法初始化当前类及bean容器,同时启动bean容器
* @param clazz 启动类
*/
public static MyApplication run(Class<?> clazz) {
if (application == null) {
application = new MyApplication();
}
if (clazz != null) {
application.scan(clazz);
}
return application;
}
/**
* 获取启动类包扫描注解,进行包扫描
* @param clazz 启动类
*/
public void scan(Class<?> clazz) {
//获取scan注解,得到扫描包范围
PackageScan PackageScan = clazz.getAnnotation(PackageScan.class);
//从注解中获取包名
String scanValue = PackageScan.value();
//如果value等于空字符串,获取启动类包路径
if ("".equals(scanValue)) {
scanValue = clazz.getPackage().getName();
}
//初始化扫描器
Reflections ref = new Reflections(scanValue);
// 获取包下所有有component注解的对象的bean对象
Set<Class<?>> classSet = ref.getTypesAnnotatedWith(Component.class);
//初始化ioc容器
init(classSet);
}
/**
* 初始化容器, 将含有component的类存入容器中
*/
private void init(Set<Class<?>> classSet) {
//获取含有Competent注解的类存入map容器
for (Class<?> aClass : classSet) {
try {
applicationContext.push(aClass);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//获取含有AutoWired注解的属性类,注入含有Competent类中
for (Class<?> aClass : classSet) {
try {
injectionObject(aClass);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* 将容器中的实例中标记有@AutoWired注解的属性注入相应的对象
*/
private void injectionObject(Class<?> aClass) {
//获取当前类成员属性
Field[] fields = aClass.getDeclaredFields();
//获取类示例
Object clazzObject = applicationContext.getObject(aClass);
for (Field field : fields) {
//初始化属性上的AutoWired注解
AutoWired autoWired = field.getAnnotation(AutoWired.class);
//判断属性上是否存在注解
if (autoWired != null) {
//判断容器中是否存在成员属性类
if (applicationContext.getObject(autoWired.classes()) == null) {
throw new HasNoBeanException("bean容器不存在指定的bean对象,请检查注入类对象上是否包含@Component注解");
}
try {
//开启访问
field.setAccessible(true);
//获取注入的属性类
Object fieldObject = applicationContext.getObject(autoWired.classes());
//将类注入属性
field.set(clazzObject, fieldObject);
} catch (Exception e) {
throw new AttributeInjectionException("注入属性失败");
}
}
}
}
}
1. MyApplication():实例化bean容器
2.run(Class<?> clazz) :ioc容器启动方法
3.scan(Class<?> clazz):扫描包路径,寻找含有component的bean对象
4.init(Set<Class<?>> classSet):将bean对象存入bean容器,并进行成员变量属性注入
5.injectionObject(Class<?> clazz):寻找当前类是否包含autowired,如果有则注入
6.cglib动态代理
package com.xy.ioc.implement;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 业务代理工厂类
*
* 需要方法增强的类使用cglib代理
*
* jdk11以上添加vm启动参数(重要) :--add-opens java.base/java.lang=net.sf.cglib --add-opens java.base/sun.net.util=net.sf.cglib
*
* 代理类包路径需要在module-info.java中开放访问,否则会报异常
*/
public class CglibProxyFactory {
/**
* 获取代理对象
*
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getProxy(Class<T> clazz) {
//创建增强器对象
Enhancer enhancer = new Enhancer();
//为将要生成的代理对象设置父类
enhancer.setSuperclass(clazz);
//设置代理对象调用业务方法时的统一处理 Ctrl+H 查看类的继承体系结构
enhancer.setCallback(new MethodInterceptor() {
/**
* 通过代理对象对所有业务方法的统一处理
*
* @param proxy 代理对象
* @param method 代理对象调用的方法
* @param args 方法的参数
* @param methodProxy 方法代理对象
* @return 代理方法的返回值
* @throws Throwable
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object returnVal = null;
try {
//通过代理对象调用它的父类被重写的真实方法
returnVal = methodProxy.invokeSuper(proxy, args);
} catch (Exception e) {
throw e; //将业务层异常抛到表示层
} finally {
//System.out.println("最终");
}
return returnVal;
}
});
//生成代理对象
return (T) enhancer.create();
}
}
cglib动态代理,用于方法使用时前后增强,高版本jdk需module.info中在开放依赖类包目录访问,以及添加vm启动参数,否则或出现异常:
--add-opens java.base/java.lang=net.sf.cglib
--add-opens java.base/sun.net.util=net.sf.cglib
7.需要依赖注入的类
package com.xy.controller;
import com.xy.ioc.AutoWired;
import com.xy.ioc.Component;
import com.xy.manager.ContextManager;
import com.xy.service.UserService;
import com.xy.service.impl.UserServiceImpl;
@Component
public class MainController {
@AutoWired(classes = UserServiceImpl.class)
private UserService userServiceImpl;
@AutoWired(classes = ContextManager.class)
private ContextManager contextManager;
public void get(){
userServiceImpl.hello();
contextManager.print();
}
public UserService getUserService() {
return this.userServiceImpl;
}
}
测试的controller类
8.注入的接口
package com.xy.service;
public interface UserService {
void hello();
}
9.接口实现类
package com.xy.service.impl;
import com.xy.ioc.Component;
import com.xy.service.UserService;
@Component
public class UserServiceImpl implements UserService {
@Override
public void hello() {
System.out.println("加班中");
}
}
接口及接口实现类
10.启动类
package com.xy;
import com.xy.controller.MainController;
import com.xy.ioc.PackageScan;
import com.xy.ioc.implement.ApplicationContext;
import com.xy.ioc.implement.MyApplication;
@PackageScan("com.xy")
public class MainApplication {
public static void main(String[] args) throws Exception {
MyApplication.run(MainApplication.class);
MainController object = ApplicationContext.getInstance().getObject(MainController.class);
object.get();
}
}
1.MyApplication.run启动ioc容器,参数为当前main方法启动类;
2.package(指定路径会去扫指定路径下的目录,没有指定会去扫描main方法启动类的包目录)注解会去扫描包路径下含有componet注解的bean对象
3.将含有注解的类反射生成cglib动态代理后将其注入bean容器中
4.将含有autowired注解的成员变量注入类属性
5.直接调用(和spring一样)
三.运行结果
四.总结
代码功能比较简单,没有使用三级缓存解决循环依赖的问题,关于这个问题,我的看法是在实际的开发过程中尽量避免出现循环依赖的问题。还有新版spring已不再解决循环依赖问题了。代码还有很多不足,如有不正之处,欢迎在评论区指正,共同进步