简单实现Spring基于注解配置
ComponentScan
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String value() default "";
}
相当于component-scan
HspSpringConfig
@ComponentScan(value = "spring.write.component")
public class HspSpringConfig {
}
替代bean.xml文件,添加@ComponentScan,获得扫描的包
AppMain
public class AppMain {
public static void main(String[] args) {
HspApplicationContext ioc = new HspApplicationContext(HspSpringConfig.class);
Object userDao = ioc.getBean("userDao");
System.out.println(userDao);
}
}
HspApplicationContext
public class HspApplicationContext {
private Class configClass;
private final ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>();
public HspApplicationContext(Class configClass) {
//1、获得扫描包路径
//得到config文件的.class类型
this.configClass = configClass;
//反射得到ComponentScan注解
ComponentScan componentScan =
(ComponentScan)configClass.getDeclaredAnnotation(ComponentScan.class);
//获取注解的value就是扫描的包路径
String path = componentScan.value();
System.out.println(path);
//spring.write.component
//2、得到包下的所有.class
//得到类的加载器,获取实际目录下的(out),
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
//URL必须按照斜杠/来写
//path = spring.write.component
path = path.replace(".","/");
URL resource = classLoader.getResource(path);
System.out.println(resource);
//file:/D:/Atest/spring/out/production/spring/spring/write/component
//对路径下的文件进行遍历
File file = new File(resource.getFile());
if(file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
//只处理.class文件(java文件)
String fileAbsolutePath = f.getAbsolutePath();
if(fileAbsolutePath.endsWith(".class")) {
System.out.println(fileAbsolutePath);
//D:\Atest\spring\out\production\spring\spring\write\component\UserDao.class
//前面已经有了path,还需要具体的类名进行反射,放入容器
String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
String classFullName = path.replace("/", ".") + "." + className;
//判断该类是不是需要注入到容器,有无注解
try {
Class<?> aClass = classLoader.loadClass(classFullName);
//判断该类的实例是否有注解
if(aClass.isAnnotationPresent(Component.class) ||
aClass.isAnnotationPresent(Controller.class) ||
aClass.isAnnotationPresent(Service.class) ||
aClass.isAnnotationPresent(Repository.class)) {
//查看是否指定了id
if(aClass.isAnnotationPresent(Component.class)) {
//只演示了Component
Component component = aClass.getDeclaredAnnotation(Component.class);
String id = component.value();
if(! "".endsWith(id)) {
className = id;
}
}
//放入容器
Class<?> clazz = Class.forName(classFullName);
Object instance = clazz.newInstance();
//类名首字母小写存入,springframework下的工具类
ioc.put(StringUtils.uncapitalize(className),instance);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public Object getBean(String name) {
return ioc.get(name);
}
}
Spring整体架构分析
没有加@Scope(value="prototype")就是单例
ioc.getBean("name"),先到BeanDefinition Map获取,未找到异常处理,
如果是单例(single)就从单例Bean Map获取
如果是多例(prototype)就创建bean对象并返回(到BeanDefinition Map中,得到Bean的clazz对象,使用反射,创建bean返回)
1、实现扫描包,得到bean的class对象
Spring基于注解配置已经写过
HspApplicationContext
public class HspApplicationContext {
private Class configClass;
public HspApplicationContext(Class configClass) {
this.configClass = configClass;
ComponentScan componentScan =
(ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
String path = componentScan.value();
System.out.println(path);//com.spring.component
ClassLoader classLoader =
HspApplicationContext.class.getClassLoader();
path = path.replace(".", "/");
System.out.println(path);//com/spring/component
URL resource =
classLoader.getResource(path);
File file = new File(resource.getFile());
if(file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String fileAbsolutePath = f.getAbsolutePath();
if(fileAbsolutePath.endsWith(".class")) {
String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
String classFullName = path.replace("/", ".") + "." + className;
try {
Class<?> clazz = classLoader.loadClass(classFullName);
if(clazz.isAnnotationPresent(Component.class)) {
System.out.println("是Spring bean【class对象】= " + clazz + " 【类名】 = " + className);
} else {
System.out.println("不是Spring bean【class对象】= " + clazz + " 【类名】 = " + className);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
2、扫描bean信息,封装到BeanDefinition对象并放入Map
增加@Scope注解来判断单例(single)或者多例(prototype)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
String value() default "";
}
BeanDefinition用于封装/记录Bean信息
1、单例/多例
2、多例需要动态生成,存放Bean对应的Class对象,反射生成
public class BeanDefinition {
private String scope;
private Class clazz;
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
@Override
public String toString() {
return "BeanDefinition{" +
"scope='" + scope + '\'' +
", clazz=" + clazz +
'}';
}
}
HspApplicationContext
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap =
new ConcurrentHashMap<>();
//单例对象类型不确定,用Object
private ConcurrentHashMap<String, Object> singletonObejcts =
new ConcurrentHashMap<>();
如果有@Component,就放入beanDefinitionMap中
可以将1、2步写成一个方法,在构造器里调用
3、初始化bean单例池并完成getBean、createBean方法
public class HspApplicationContext {
private Class configClass;
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap =
new ConcurrentHashMap<>();
//单例对象类型不确定,用Object
private ConcurrentHashMap<String, Object> singletonObejcts =
new ConcurrentHashMap<>();
public HspApplicationContext(Class configClass) {
//完成扫描指定包
beanDefinitionScan(configClass);
//遍历所有的beanDefinition对象
Enumeration<String> keys = beanDefinitionMap.keys();
while(keys.hasMoreElements()) {
String beanName = keys.nextElement();
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
Object bean = createBean(beanDefinition);
singletonObejcts.put(beanName,bean);
}
}
System.out.println("singletonObejcts单例池=" + singletonObejcts);
System.out.println("beanDefinitionMap=" + beanDefinitionMap);
}
public void beanDefinitionScan(Class configClass) {}
public Object createBean(BeanDefinition beanDefinition) {
Class clazz = beanDefinition.getClazz();
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
public Object getBean(String name) {
//判断beanName是否存在
if(beanDefinitionMap.containsKey(name)) {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
return singletonObejcts.get(name);
} else {
return createBean(beanDefinition);
}
} else {
throw new NullPointerException("没有该Bean");
}
}
}
4、依赖注入
增加@Autowired注解,这里只用名字来进行匹配
public Object createBean(BeanDefinition beanDefinition) {
Class clazz = beanDefinition.getClazz();
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
//遍历所有字段,
for(Field field : clazz.getDeclaredFields()) {
//是否有Autowired
if(field.isAnnotationPresent(Autowired.class)) {
String name = field.getName();
//通过getBean获取要组装的对象
Object bean = getBean(name);
//进行组装,private需要暴破
field.setAccessible(true);
field.set(instance,bean);//将 bean 赋值给 instance 的 field
}
}
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
5、bean后置处理器实现
原生Spring接口InitializingBean(初始化),自己实现这个接口,完成初始化方法
接口中有afterPropertiesSet()方法,在Bean的setter方法执行完毕后,被spring容器调用,就是初始化方法
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
应用:选择MonsterService来实现这个接口
@Component("monsterService")
@Scope(value = "property")
public class MonsterService implements InitializingBean {
@Autowired
private MonsterDao monsterDao;
public void m1() {
monsterDao.hi();
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("monsterService初始化方法被调用");
}
}
在创建好Bean实例后,判断是否需要初始化
容器中常用的一个方法是:根据该类是否实现了某个接口,来判断是否要执行某个业务(接口编程)
在HspApplicationContext的createBean返回instance之前加上判断是否是这个接口的子类型,是的话就执行初始化方法
判断如果返回为null,不变化
加上beanName
public Object createBean(String beanName, BeanDefinition beanDefinition) {
Class clazz = beanDefinition.getClazz();
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
//遍历所有字段,
for(Field field : clazz.getDeclaredFields()) {
//是否有Autowired
if(field.isAnnotationPresent(Autowired.class)) {
String name = field.getName();
//通过getBean获取要组装的对象
Object bean = getBean(name);
//进行组装,private需要暴破
field.setAccessible(true);
field.set(instance,bean);//将 bean 赋值给 instance 的 field
}
}
System.out.println("======创建好实例======" + instance);
//初始化方法前,调用before方法,可以对容器的bean实例进行处理,然后返回处理后的bean
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
Object current = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
if(current != null)
instance = current;
}
if(instance instanceof InitializingBean) {
try {
((InitializingBean) instance).afterPropertiesSet();//将instance转成InitializingBean类型,调用方法
} catch (Exception e) {
e.printStackTrace();
}
}
//初始化方法后,调用after方法,可以对容器的bean实例进行处理,然后返回处理后的bean
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
Object current = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
if(current != null)
instance = current;
}
return instance;
后置处理器接口BeanPostProcessor
对容器中的所有bean生效
public interface BeanPostProcessor {
//bean的初始化前调用
default Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
//bean的初始化后调用
default Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
自己写一个类实现后置处理器,通过Component注入到容器中
实现类可以不止一个,放在Arraylist中
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
@Component
public class HspBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("后置处理器before()");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("后置处理器after()");
return bean;
}
}
在HspApplicationContext的扫描方法中扫描Component,再判断是否实现了后置处理器接口
6、AOP机制实现
原生Spring实现方法
A接口写方法,B类实现A接口,给B类加上@Component注入到容器
切面类加上@Component和@Aspect
B类执行后置处理器的After方法后,变成代理对象
public interface SmartAnimalable {
float getSum(float i, float j);
float getSub(float i, float j);
}
@Component(value = "smartDog")
public class SmartDog implements SmartAnimalable {
public float getSum(float i, float j) {
float res = i + j;
System.out.println("SmartDog-getSum-res=" + res);
return res;
}
public float getSub(float i, float j) {
float res = i - j;
System.out.println("SmartDog-getSub-res=" + res);
return res;
}
}
public class SmartAnimalAspect {
public static void showBeginLog() {
System.out.println("前置通知..");
}
public static void showSuccessLog() {
System.out.println("返回通知..");
}
}
在HspBeanPostProcessor的after方法中实现AOP(写死的方法)
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("后置处理器after()");
if("smartDog".equals(beanName)) {
Object proxyInstance = Proxy.newProxyInstance(HspBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
if("getSum".equals(method.getName())) {
SmartAnimalAspect.showBeginLog();
result = method.invoke(bean,args);
SmartAnimalAspect.showSuccessLog();
} else {
result = method.invoke(bean,args);
}
return result;
}
});
return proxyInstance;
}
return bean;
}