1.了解Spring工作的大概流程
2.属性BeanDefinition,BeanFactory,Bean等基本概念
3.熟悉Bean的生命周期,Bean的后置处理器等基本概念
1.首先我们可以先自定义几个注解@Componet
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Componet {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Lazy {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value() default "";
}
2.我们定义一个自己的启动类
/**
* 1.自定义注解:Componet
* 2.创建LubanApplicationContext
* LubanApplicaitonContext的作用就是启动spring,帮助我们去创建bean,这样我们才能在下面进行getBean
* 启动的时候就直接创建吗?启动spring,难道所有的类都要创建bean,当然不是,首先我们要确定发扫描路径,所以我们要进行扫描
*
* 步骤:启动 扫描(确定包路径) 只有加了@conponet注解的才创建 创建bean(非懒加载的单例Bean)
*/
public class Application {
public static void main(String[] args) {
LubanApplicaitonContext context=new LubanApplicaitonContext(Appconfig.class);
TestService testService = (TestService) context.getBean("testService");
testService.test();
//接下来实现自动注入的功能:什么时候来自动注入的呢?在createBean的时候,我们创建完一个Bean,需要属性及逆行填充
}
}
那么我们怎么来确定扫描的路径呢?当然自己手写一个Appconfig,并加上我们的@ComponetScan
import com.luban.framework.ComponetScan;
@ComponetScan("com.luban.service")
public class Appconfig {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponetScan {
String value() default "";
}
那么我们就开始沿着我们的步骤来:启动 扫描(确定包路径) 只有加了@conponet注解的才创建 创建bean(非懒加载的单例Bean)
环节2:扫描
ublic class LubanApplicaitonContext {
private Class appconfigClass;
private Map<String,BeanDefinition> beanDefinitionMap=new HashMap<>();//beandefinitionmap
private Map<String,Object> singletonObjects=new HashMap<>();//单例池
private List<BeanPostProcessor> BeanPostProcessors=new ArrayList<>();//后置处理器
public LubanApplicaitonContext(Class appconfigClass) {
this.appconfigClass = appconfigClass;
//扫描
scan(appconfigClass);
//创建非懒加载的单例Bean
createNonLazySingleton();
}
//首先来看扫描scan(appconfigClass);
public void scan(Class appconfigClass){//获得我们的Appconfig
if (appconfigClass.isAnnotationPresent(ComponetScan.class)) {//看我们的Appconfig有没有ComponetScan这个注解
ComponetScan componetScanAnnotation = (ComponetScan) appconfigClass.getAnnotation(ComponetScan.class);//获得注解
String path = componetScanAnnotation.value();//获得注解的名字,也即是我们的扫描路径
//其实扫描路径是classes下面的class文件并不是.java文件,所以获得的com.luban.service就只是我们的包名
//-classpath: E:\JAVA\JavaSE\Test2\target\classes 这个就是我们的路径名
System.out.println(path);//com.luban.service
path= path.replace(".","/");
//因为我们的类路径是由AppClassLoader加载的,所以我们可以使用类加载器
ClassLoader classLoader=LubanApplicaitonContext.class.getClassLoader();
URL resource = classLoader.getResource(path);//获取一个资源,里面我们可以传一个相对路径,相对于我们的-calsspath: E:\JAVA\JavaSE\Test2\target\classes正符合要求
File file=new File(resource.getFile());//此时我们得到的就是一个文件夹 service
for (File f : file.listFiles()) {//E:\JAVA\JavaSE\Test2\target\classes\com\luban\service\OrderService.class
//此时我们就得到了Class文件,转成Class对象下面我们的思路就是判断是否存在@componet注解,其实在spring中就是使用ASM技术直接去判断字节码
//如何得到呢Class对象呢?还是使用classLoader
String s = f.getAbsolutePath();
if (s.endsWith(".class")) {
s=s.substring(s.indexOf("com"),s.indexOf(".class"));
s=s.replace("\\",".");//s :com.luban.service.Testservice
try {
Class clazz = classLoader.loadClass(s);//获取需要加载类的Class对象
System.out.println(clazz);
//我们确定了扫描的路径,下面就是确定那个类可以成为一个bean了
if (clazz.isAnnotationPresent(Componet.class)) {//是否存在这个@Componet注解
//BeanPostProcessor先不用看,我一会会说
/*if(BeanPostProcessor.class.isAssignableFrom(clazz)){//判断这个类是一个BeanPostProcessor
BeanPostProcessor declaredConstructor = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
BeanPostProcessors.add(declaredConstructor);
}*/
//有componet就证明这是一个Bean,但是创建的话,需要判断是不是非懒加载的单例Beanc
//获取Component注解的信息,其实就是componet的beanName
//Beandefinition把我对bean的解析存放起来,这样在getBean的时候就可以直接拿
BeanDefinition beanDefinition=new BeanDefinition();
beanDefinition.setBeanClass(clazz);
Componet Componetannotation = (Componet) clazz.getAnnotation(Componet.class);
String beanName = Componetannotation.value();//componet配置的beanName
if (clazz.isAnnotationPresent(Lazy.class)) {//是不是懒加载的
beanDefinition.setLazy(true);
}
if(clazz.isAnnotationPresent(Scope.class)){
Scope Scopeannotation = (Scope) clazz.getAnnotation(Scope.class);
String value = Scopeannotation.value();//获取Scope的值
beanDefinition.setScope(value);
}else {
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName,beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
现在我们先看一下getBean,引进来beandefinition
/**
* bean对象和Beandefinition,现有Beandefinition
*/
public class BeanDefinition {
private String Scope;
private boolean isLazy;
private Class beanClass;
public String getScope() {
return Scope;
}
public void setScope(String scope) {
Scope = scope;
}
public boolean isLazy() {
return isLazy;
}
public void setLazy(boolean lazy) {
isLazy = lazy;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
}
public Object getBean(String beanName) {
//如果我能确定这个beanName对应的就是这个类,那么我还要看一下这个类是单例的还是原型的
//所以说,我还要在getBean里面去解析这个类,
//是单例,单例池中拿,原型,在创建一个,spring是只判断一次的,这就牵扯到了Beandefinition
//也就是把bean的解析存储起来 scope lazy
if (!beanDefinitionMap.containsKey(beanName)) {
throw new NullPointerException();
}else {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition.getScope().equals("singleton")){
//从单例池中获取
Object o = singletonObjects.get(beanName);
if(o==null){//如果单例池中不存在,就创建一个,放进去
Object bean = createBean(beanDefinition,beanName);
singletonObjects.put(beanName,bean);
}
return o;
}else if(beanDefinition.getScope().equals("prototype")){
//重新创建一个 并返回
Object bean = createBean(beanDefinition,beanName);
return bean;
}
}
return null;
}
环节3:创建非懒加载的单例Bean
private void createNonLazySingleton() {
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition.getScope().equals("singleton")&& !beanDefinition.isLazy()){
Object bean = createBean(beanDefinition,beanName);//如果是单例,那么我们就需要吧我们的bean放到到单例池当中
singletonObjects.put(beanName,bean);
}
}
}
private Object createBean(BeanDefinition beanDefinition,String beanName){
//怎样去创建一个Bean呢?
Class beanClass = beanDefinition.getBeanClass();
try {
Object instance = beanClass.getDeclaredConstructor().newInstance();//这个时候Bean已经创建好了,下面就是一些扩展
//最后知识点 Bean的后置处理器
//如果我们在每个属性上加上了@Autowired和@resources,那么我们需要分开来处理
//同时@Autowired使用的是AutowiredAnnotationBeanPostProcessor,@Reources使用的是CommAnnotationBeanPostProcessor
//spring还给我们提供了自定义,
for (BeanPostProcessor beanPostProcessor : BeanPostProcessors) {
beanPostProcessor.Autowired();
}
//填充属性 1、遍历字段,也就是你的加了@Autowired注解的才填充
/*for (Field field : beanClass.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
//我要给这个属性赋什么值呢?这个值又从哪里来呢?
//这里就涉及了ByName,ByType 单例模式和单例Bean是不一样的,单例模式:整个JVM中只有一个对象,但是单例Bean呢 两个@Bean也完全没有问题
//所以Autowired是先按照类型来找,有可能拿到多个,这种情况下就可以是哟个ByName来唯一的获取一个
//为什么不直接按照ByName呢?因为名字虽然对上,但类型对不上,会更加的没用,@Resource就是先使用的ByName,这个和JNDI很相似,因为name---资源
String name = field.getName();
Object bean = getBean(name);
field.setAccessible(true);//开启
field.set(instance,bean);
}
}*/
if(instance instanceof BeanNameAware){
((BeanNameAware) instance).setName(beanName);
}
if(instance instanceof InitializingBean){
((InitializingBean) instance).afterpropertiesSet();//执行的时机
}
return instance;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
延申段~~~
@Autowired
@Componet("testService")
@Scope("prototype")
public class TestService {//当一个bean想知道自己的名字的时候,可以实现这个接口
@Autowired //做一些初始化的逻辑
private OrderService orderService;
private String beanName;
public OrderService getOrderService() {
return orderService;
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void test(){
System.out.println(orderService);
System.out.println(beanName);;
}
}
@Autowired的时机就是创建好了Bean,然后对属性进行填充,这可能牵扯到先后加载的问题,我们在getName的时候做了判断,如果属性填充的bean不存在,就其创建一个,加入单例池
private Object createBean(BeanDefinition beanDefinition,String beanName){
//怎样去创建一个Bean呢?
Class beanClass = beanDefinition.getBeanClass();
try {
Object instance = beanClass.getDeclaredConstructor().newInstance();
//填充属性 1、遍历字段,也就是你的加了@Autowired注解的才填充
for (Field field : beanClass.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
//我要给这个属性赋什么值呢?这个值又从哪里来呢?
//这里就涉及了ByName,ByType 我只写了ByName的方式单例模式和单例Bean是不一样的,单例模式:整个JVM中只有一个对象,但是单例Bean呢 两个@Bean也完全没有问题,只要是BeanName不一样就OK
//所以Autowired是先按照类型来找,有可能拿到多个,这种情况下再使用ByName来唯一的获取一个
//为什么不直接按照ByName呢?因为名字虽然对上,但类型对不上,会更加的没用,@Resource就是先使用的ByName,这个和JNDI很相似,因为name---资源
String name = field.getName();//我们是简单的按照属性名来进行
Object bean = getBean(name);
field.setAccessible(true);//开启
field.set(instance,bean);//给那个对象,填充什么值
}
}
if(instance instanceof BeanNameAware){
((BeanNameAware) instance).setName(beanName);
}
if(instance instanceof InitializingBean){
((InitializingBean) instance).afterpropertiesSet();//执行的时机
}
return instance;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
BeanNameAware和InitializingBean
ublic class TestService implements BeanNameAware, InitializingBean {//当一个bean想知道自己的名字的时候,可以实现这个接口
@Autowired //InitializingBean做一些初始化的逻辑
private OrderService orderService;
private String beanName;//我想使用beanName来存储这个类的beanName;我们可以写一个这样的接口
public OrderService getOrderService() {
return orderService;
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void test(){
System.out.println(orderService);
System.out.println(beanName);;
}
@Override
public void setName(String name) {//重写这个方法
this.beanName=name;
}
@Override
public void afterpropertiesSet() {//可以对我们bean里面的一些属性进行验证
if(orderService==null){
//抛异常
}
}
}
package com.luban.framework;
public interface BeanNameAware {
public void setName(String name);
}
public interface InitializingBean {
public void afterpropertiesSet();
}
逻辑判断在哪儿?、
private Object createBean(BeanDefinition beanDefinition,String beanName){
//怎样去创建一个Bean呢?
Class beanClass = beanDefinition.getBeanClass();
try {
Object instance = beanClass.getDeclaredConstructor().newInstance();
//填充属性 1、遍历字段,也就是你的加了@Autowired注解的才填充
for (Field field : beanClass.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
//我要给这个属性赋什么值呢?这个值又从哪里来呢?
//这里就涉及了ByName,ByType 单例模式和单例Bean是不一样的,单例模式:整个JVM中只有一个对象,但是单例Bean呢 两个@Bean也完全没有问题
//所以Autowired是先按照类型来找,有可能拿到多个,这种情况下就可以是哟个ByName来唯一的获取一个
//为什么不直接按照ByName呢?因为名字虽然对上,但类型对不上,会更加的没用,@Resource就是先使用的ByName,这个和JNDI很相似,因为name---资源
String name = field.getName();
Object bean = getBean(name);
field.setAccessible(true);//开启
field.set(instance,bean);
}
}
if(instance instanceof BeanNameAware){//填充完属性在进行设置
((BeanNameAware) instance).setName(beanName);
}
if(instance instanceof InitializingBean){
((InitializingBean) instance).afterpropertiesSet();//执行的时机
}
return instance;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
BeanPostProcessor
public class TestService implements BeanNameAware, InitializingBean {//当一个bean想知道自己的名字的时候,可以实现这个接口
@Autowired //做一些初始化的逻辑
private OrderService orderService;
@Resources
private UserService userService;
private String beanName;
//存在这样的情况,一个类中使用的是@Autowired,另一个使用的是@Reources,如果解析的话,会分开解析,因为它们两个使用的后置处理器也不一样,Autowired使用的是AutowiredAnnotationBeanPostProcessor,而@Resources使用的就是CommonAnnotationBeanPostProcessor,而且我们还可以自定义注解,自己写BeanPostProcessor
public interface BeanPostProcessor {
public void Autowired();
}
@Componet
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
@Override
public void Autowired() {
System.out.println("Autowired注解");
}
}
@Componet
public class CommonAnnotationBeanPostProcessor implements BeanPostProcessor {
@Override
public void Autowired() {
System.out.println("Resource注解");
}
}
@Componet
public class LubanAnnotationBeanPostProcessor implements BeanPostProcessor {
@Override
public void Autowired() {
System.out.println("LubanAutowiredBeanPostProccessor注解");
}
}
这三个都是组件,把他们加入到spring容器中。
判断逻辑在scan中也存在
if (clazz.isAnnotationPresent(Componet.class)) {
if(BeanPostProcessor.class.isAssignableFrom(clazz)){//判断这个类是一个BeanPostProcessor
BeanPostProcessor declaredConstructor = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
BeanPostProcessors.add(declaredConstructor);
}
//有componet就证明这是一个Bean,但是创建的话,需要判断是不是非懒加载的单例Beanc
//获取Component注解的信息
BeanDefinition beanDefinition=new BeanDefinition();
beanDefinition.setBeanClass(clazz);
Componet Componetannotation = (Componet) clazz.getAnnotation(Componet.class);
String beanName = Componetannotation.value();//componey配置的beanName
if (clazz.isAnnotationPresent(Lazy.class)) {
beanDefinition.setLazy(true);
}
if(clazz.isAnnotationPresent(Scope.class)){
Scope Scopeannotation = (Scope) clazz.getAnnotation(Scope.class);
String value = Scopeannotation.value();//获取Scope的值
beanDefinition.setScope(value);
}else {
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName,beanDefinition);
}
private Object createBean(BeanDefinition beanDefinition,String beanName){
//怎样去创建一个Bean呢?
Class beanClass = beanDefinition.getBeanClass();
try {
Object instance = beanClass.getDeclaredConstructor().newInstance();
//最后知识点 Bean的后置处理器
//如果我们在每个属性上加上了@Autowired和@resources,那么我们需要分开来处理
//同时@Autowired使用的是AutowiredAnnotationBeanPostProcessor,@Reources使用的是CommAnnotationBeanPostProcessor
//spring还给我们提供了自定义,
for (BeanPostProcessor beanPostProcessor : BeanPostProcessors) {
beanPostProcessor.Autowired();//这个里面就是我们去判断注解是@Resources还是@Autowired的逻辑了
}
if(instance instanceof BeanNameAware){
((BeanNameAware) instance).setName(beanName);
}
if(instance instanceof InitializingBean){
((InitializingBean) instance).afterpropertiesSet();//执行的时机
}
return instance;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
因为:public class TestService implements BeanNameAware, InitializingBean {//当一个bean想知道自己的名字的时候,可以实现这个接口
@Autowired //做一些初始化的逻辑
private OrderService orderService;
@Resources
private UserService userService;
//有两个这样的注解,所以执行了两次,其实应该在那三个BeanpostProcessor中去判断的,就可以实现不同的BeanPostProcessor去解析@Autowired和@Resources了