实现Spring底层机制
【初始化 IOC 容器+依赖注入+BeanPostProcessor 机制+AOP】
搭建Maven项目


加入依赖的包
修改pom.xml
<dependencies>
<!--加入spring开发的基本包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.8</version>
</dependency>
<!--加入spring开发切面编程需要的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.8</version>
</dependency>
</dependencies>
目录结构

package com.lzw.spring.component;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* @author LiAng
* 就是一个Controller
*/
//也可以使用@Controller
//在默认情况下,我们配置@Component @Controller @Service @Repository是单例
//@Scope(value = "prototype") 表示以多实例形式,返回UserAction bean
@Component
@Scope(value = "prototype")
public class UserAction {
}
package com.lzw.spring.component;
import org.springframework.stereotype.Component;
/**
* @author LiAng
*/
//也可以使用@Repository
@Component
public class UserDao {
public void hi(){
System.out.println("UserDao-hi()---");
}
}
package com.lzw.spring.component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author LiAng
*/
//也可以使用@Service
@Component
public class UserService {
//定义属性
//思考:加入 @Autowired,Spring容器是如何实现依赖注入
//也可以使用@Resource
@Autowired
private UserDao userDao;
public void m1(){
userDao.hi();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置自动扫描的包-->
<!--
1. 如果我们是普通的java项目, beans.xml 放在src下
2. 如果我们是java maven 项目, beans.xml 放在 src/main/resources
-->
<context:component-scan base-package="com.lzw.spring.component"/>
</beans>
package com.lzw.spring;
import com.lzw.spring.component.UserAction;
import com.lzw.spring.component.UserDao;
import com.lzw.spring.component.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author LiAng
*/
public class AppMain {
public static void main(String[] args) {
//测试是否可以得到spring容器中的bean,同时看看依赖注入是否ok
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
UserAction userAction = (UserAction)ioc.getBean("userAction");
UserAction userAction2 = (UserAction)ioc.getBean("userAction");
System.out.println("userAction = " + userAction);
System.out.println("userAction2 = " + userAction2);
UserDao userDao = (UserDao) ioc.getBean("userDao");
System.out.println("userDao = " + userDao);
UserService userService = (UserService) ioc.getBean("userService");
System.out.println("userService = " + userService);
//测试一下当前的依赖注入
userService.m1();
}
}

思考问题
- Spring 底层实现,如何实现 IOC 容器创建和初始化。
- Spring 底层实现,如何实现 getBean,根据 singleton 和 prototype 来返回 bean 实例。
继续思考-原生 Spring 如何实现 BeanPostProcessor
代码演示
创建MyBeanPostProcessor.java
package com.lzw.spring.proces;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author LiAng
* 编写的一个后置处理器
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 在Bean的init初始化方法前调用
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization() 被调用" + beanName + " bean=" + bean.getClass());
return bean;
}
/**
* 在Bean的init初始化方法后调用
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization() 被调用" + beanName + " bean=" + bean.getClass());
return bean;
}
}
修改beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置自动扫描的包-->
<!--
1. 如果我们是普通的java项目, beans.xml 放在src下
2. 如果我们是java maven 项目, beans.xml 放在 src/main/resources
-->
<context:component-scan base-package="com.lzw.spring.component"/>
<!--配置后置处理器-->
<bean class="com.lzw.spring.process.MyBeanPostProcessor" id="myBeanPostProcessor"/>
</beans>
修改UserService.java
package com.lzw.spring.component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author LiAng
*/
//也可以使用@Service
@Component
public class UserService {
//定义属性
//思考:加入 @Autowired,Spring容器是如何实现依赖注入
//也可以使用@Resource
@Autowired
private UserDao userDao;
public void m1(){
userDao.hi();
}
//这里我们需要指定init() 是初始化方法
@PostConstruct
public void init(){
System.out.println("UserService-init()");
}
}
修改UserAction.java
package com.lzw.spring.component;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* @author LiAng
* 就是一个Controller
*/
//也可以使用@Controller
//在默认情况下,我们配置@Component @Controller @Service @Repository是单例
//@Scope(value = "prototype") 表示以多实例形式,返回UserAction bean
//思考:Spring容器底层如何实现
@Component
//@Scope(value = "prototype")
public class UserAction {
}

继续思考-原生 Spring 是如何实现 AOP
代码演示
package com.lzw.spring.aop;
/**
* @author LiAng
*/
public interface SmartAnimalable {
float getSum(float i, float j);
float getSub(float i, float j);
}
package com.lzw.spring.aop;
import org.springframework.stereotype.Component;
/**
* @author LiAng
*/
@Component
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;
}
}
package com.lzw.spring.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @author LiAng
* 这是一个切面类
*/
@Aspect
@Component
public class SmartAnimalAspect {
//给SmartDog配置前置,返回,异常,最终通知
//前置通知
@Before(value = "execution(public float com.lzw.spring.aop.SmartDog.getSum(float, float))")
public void showBeginLog(JoinPoint joinPoint) {
//通过连接点对象joinPoint 可以获取方法签名
Signature signature = joinPoint.getSignature();
System.out.println("SmartAnimalAspect-切面类showBeginLog()-方法执行前-日志-方法名-" + signature.getName() + "-参数 "
+ Arrays.asList(joinPoint.getArgs()));
}
//返回通知
@AfterReturning(value = "execution(public float com.lzw.spring.aop.SmartDog.getSum(float, float))", returning = "res")
public void showSuccessEndLog(JoinPoint joinPoint, Object res) {
Signature signature = joinPoint.getSignature();
System.out.println("SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() + " 返回的结果是=" + res);
}
//异常通知
@AfterThrowing(value = "execution(public float com.lzw.spring.aop.SmartDog.getSum(float, float))", throwing = "throwable")
public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {
Signature signature = joinPoint.getSignature();
System.out.println("SmartAnimalAspect-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName() + " 异常信息=" + throwable);
}
//最终通知
@After(value = "execution(public float com.lzw.spring.aop.SmartDog.getSum(float, float))")
public void showFinallyEndLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
System.out.println("SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-" + signature.getName());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置自动扫描的包-->
<!--
1. 如果我们是普通的java项目, beans.xml 放在src下
2. 如果我们是java maven 项目, beans.xml 放在 src/main/resources
-->
<context:component-scan base-package="com.lzw.spring.component"/>
<context:component-scan base-package="com.lzw.spring.aop"/>
<!--开启基于注解的AOP功能-->
<aop:aspectj-autoproxy/>
<!--配置后置处理器-->
<bean class="com.lzw.spring.process.MyBeanPostProcessor" id="myBeanPostProcessor"/>
</beans>
package com.lzw.spring;
import com.lzw.spring.aop.SmartAnimalable;
import com.lzw.spring.component.UserAction;
import com.lzw.spring.component.UserDao;
import com.lzw.spring.component.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author LiAng
*/
public class AppMain {
public static void main(String[] args) {
//测试是否可以得到spring容器中的bean,同时看看依赖注入是否ok
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
UserAction userAction = (UserAction)ioc.getBean("userAction");
UserAction userAction2 = (UserAction)ioc.getBean("userAction");
System.out.println("userAction = " + userAction);
System.out.println("userAction2 = " + userAction2);
UserDao userDao = (UserDao) ioc.getBean("userDao");
System.out.println("userDao = " + userDao);
UserService userService = (UserService) ioc.getBean("userService");
System.out.println("userService = " + userService);
//测试一下当前的依赖注入
userService.m1();
//测试一下AOP
SmartAnimalable smartDog = ioc.getBean(SmartAnimalable.class);
smartDog.getSum(10,2);
}
}

简单分析 AOP 和 BeanPostProcessor 关系
- AOP 实现 Spring 可以通过给一个类,加入注解 @EnableAspectJAutoProxy。

- 追一下 @EnableAspectJAutoProxy 源码。







解读
- AOP 底层是基于 BeanPostProcessor 机制的。
- 即在 Bean 创建好后,根据是否需要 AOP 处理,决定返回代理对象,还是原生 Bean 。
- 在返回代理对象时,就可以根据要代理的类和方法来返回 。
- 其实这个机制并不难,本质就是在 BeanPostProcessor 机制 + 动态代理技术 。
Spring整体架构分析

阶段1-编写自己 Spring 容器,实现扫描包, 得到 bean 的 class 对象
类加载器
java 的类加载器 3 种
Bootstrap 类加载器--------------对应路径 jre/lib
Ext 类加载器--------------------对应路径 jre/lib/ext
App 类加载器-------------------对应路径 classpath
classpath 类路径,就是 java.exe 执行时,指定的路径,比如:

"C:\Program Files (x86)\Java\jdk1.8.0_102\bin\java.exe" "-javaagent:D:\Program Files\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=3019:D:\Program Files\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_102\jre\lib\rt.jar;**E:\VIP\AllDemo\Spring5\lzw-spring\target\classes;**D:\Environment\apache-maven-3.8.4\maven-repo\org\springframework\spring-context\5.3.8\spring-context-5.3.8.jar;D:\Environment\apache-maven-3.8.4\maven-repo\org\springframework\spring-aop\5.3.8\spring-aop-5.3.8.jar;D:\Environment\apache-maven-3.8.4\maven-repo\org\springframework\spring-beans\5.3.8\spring-beans-5.3.8.jar;D:\Environment\apache-maven-3.8.4\maven-repo\org\springframework\spring-core\5.3.8\spring-core-5.3.8.jar;D:\Environment\apache-maven-3.8.4\maven-repo\org\springframework\spring-jcl\5.3.8\spring-jcl-5.3.8.jar;D:\Environment\apache-maven-3.8.4\maven-repo\org\springframework\spring-expression\5.3.8\spring-expression-5.3.8.jar;D:\Environment\apache-maven-3.8.4\maven-repo\org\springframework\spring-aspects\5.3.8\spring-aspects-5.3.8.jar;D:\Environment\apache-maven-3.8.4\maven-repo\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar" com.lzw.spring.AppMain
分析

代码实现
创建子模块 (java maven module)。




创建注解 @ComponentScan
package com.lzw.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LiAng
* 1. @Target(ElementType.TYPE)指定我们的ComponentScan注解可以修饰 Type程序元素
* 2. @Retention(RetentionPolicy.RUNTIME) 指定ComponentScan注解 保留范围
* 3. String value() default ""; 表示ComponentScan 可以传入 value
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
//通过value可以指定要扫描的包
String value() default "";
}
创建注解 @Component
package com.lzw.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LiAng
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
//通过value可以给注入的bean/对象指定名字
String value() default "";
}
创建LzwSpringConfig
package com.lzw.spring.ioc;
import com.lzw.spring.annotation.ComponentScan;
/**
* @author LiAng
* 这是一个配置类, 作用类似我们原生spring的 beans.xml 容器配置文件
*/
@ComponentScan(value = "com.lzw.spring.component")
public class LzwSpringConfig {
}
创建MonsterService
package com.lzw.spring.component;
import com.lzw.spring.annotation.Component;
/**
* @author LiAng
* 说明MonsterService 是一个Service
* 1. 如果指定了value,那么在注入spring容器时,以你指定为准
* 2. 如果没有指定value ,则使用类名首字母小写为名字
*/
@Component(value = "monsterService") //把MonsterService注入我们自己的spring容器中
public class MonsterService {
}
创建MonsterDao
package com.lzw.spring.component;
import com.lzw.spring.annotation.Component;
/**
* @author LiAng
*/
@Component(value = "monsterDao")
public class MonsterDao {
}
创建LzwSpringApplicationContext
package com.lzw.spring.ioc;
import com.lzw.spring.annotation.Component;
import com.lzw.spring.annotation.ComponentScan;
import java.io.File;
import java.net.URL;
/**
* @author LiAng
* @time 2022/6/10 17:41
* LzwSpringApplicationContext 类的作用类似Spring原生ioc容器
*/
public class LzwSpringApplicationContext {
private Class configClass;
public LzwSpringApplicationContext(Class configClass) {
this.configClass = configClass;
//获取要扫描的包
//1. 先得到LzwSpringConfig配置的的@ComponentScan(value = "com.lzw.spring.component")
ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
//2. 通过componentScan的value=> 即要扫描的包
String path = componentScan.value();
System.out.println("要扫描的包 = " + path);
//得到要扫描的包下的所有资源(类 .class)
//1.得到类的加载器->APP 类加载器
ClassLoader classLoader = LzwSpringApplicationContext.class.getClassLoader();
//2. 通过类的加载器获取到要扫描的包的资源 url=》类似一个路径
path = path.replace(".", "/");
URL resource = classLoader.getResource(path);
System.out.println("resource=" + resource);
//3. 将要加载的资源(.class) 路径下的文件进行遍历=>io
File file = new File(resource.getFile());
if(file.isDirectory()){
File[] files = file.listFiles();
for (File f : files) {
//System.out.println("==========================");
//System.out.println("="+f.getAbsolutePath());
String fileAbsolutePath = f.getAbsolutePath();
//这里我们只处理.class文件
if (fileAbsolutePath.endsWith(".class")) {
//1. 获取到类名
String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//2. 获取类的完整的路径(全类名)
//path.replace("/",".") => com.lzw.spring.component.
String classFullName = path.replace("/", ".") + "." + className;
//3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
try {
Class<?> aClazz = classLoader.loadClass(classFullName);
if(aClazz.isAnnotationPresent(Component.class)){
//如果该类使用了@Component,说明是Spring bean
System.out.println("是一个Spring bean = " + aClazz + " 类名=" + className);
}else{
//如果该类没有使用了@Component,说明不是Spring bean
System.out.println("不是一个Spring bean = " + aClazz+ " 类名=" + className);
}
}catch (Exception e){
}
}
}
System.out.println("==============================");
}
}
//返回容器中对象
public Object getBean(String name){
return null;
}
}
创建测试类 AppMain
package com.lzw.spring;
import com.lzw.spring.ioc.LzwSpringApplicationContext;
import com.lzw.spring.ioc.LzwSpringConfig;
/**
* @author LiAng
*/
public class AppMain {
public static void main(String[] args) {
LzwSpringApplicationContext lzwSpringApplicationContext = new LzwSpringApplicationContext(LzwSpringConfig.class);
}
}
此时运行可能会报错

第一个位置

第二个位置

运行结果

阶段2- 扫描将 bean 信息封装到 BeanDefinition 对象, 并放入到 Map
分析

代码实现
创建注解 @Scope
package com.lzw.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LiAng
* Scope 可以指定Bean的作用范围[singleton, prototype]
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
//通过value可以指定singleton,prototype
String value() default "";
}
修改MonsterService
@Component(value = "monsterService") //把MonsterService注入我们自己的spring容器中
@Scope(value = "prototype")
public class MonsterService {
}
创建BeanDefinition
package com.lzw.spring.ioc;
/**
* @author LiAng
* BeanDefinition 用于封装Bean的信息[1.scope 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 +
'}';
}
}
引入commans-lang包
因为要使用到它的工具类 StringUtils.uncapitalize(String str)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lzw</groupId>
<artifactId>lzw-myspring</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>
修改LzwSpringApplicationContext
package com.lzw.spring.ioc;
import com.lzw.spring.annotation.Component;
import com.lzw.spring.annotation.ComponentScan;
import com.lzw.spring.annotation.Scope;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author LiAng
* LzwSpringApplicationContext 类的作用类似Spring原生ioc容器
*/
public class LzwSpringApplicationContext {
private Class configClass;
//定义属性BeanDefinitionMap -> 存放BeanDefinition对象
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
//定义属性SingletonObjects -> 存放单例对象
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
public LzwSpringApplicationContext(Class configClass) {
beanDefinitionScan(configClass);
System.out.println("beanDefinitionMap = " + beanDefinitionMap);
}
//该方法完成对指定包的扫描,并将Bean信息封装到BeanDefinition,再放入到Map
public void beanDefinitionScan(Class configClass){
this.configClass = configClass;
//获取要扫描的包
//1. 先得到LzwSpringConfig配置的的@ComponentScan(value = "com.lzw.spring.component")
ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
//2. 通过componentScan的value=> 即要扫描的包
String path = componentScan.value();
System.out.println("要扫描的包 = " + path);
//得到要扫描的包下的所有资源(类 .class)
//1.得到类的加载器->APP 类加载器
ClassLoader classLoader = LzwSpringApplicationContext.class.getClassLoader();
//2. 通过类的加载器获取到要扫描的包的资源 url=》类似一个路径
path = path.replace(".", "/");
URL resource = classLoader.getResource(path);
System.out.println("resource=" + resource);
//3. 将要加载的资源(.class) 路径下的文件进行遍历=>io
File file = new File(resource.getFile());
if(file.isDirectory()){
File[] files = file.listFiles();
for (File f : files) {
//System.out.println("==========================");
//System.out.println("="+f.getAbsolutePath());
String fileAbsolutePath = f.getAbsolutePath();
//这里我们只处理.class文件
if (fileAbsolutePath.endsWith(".class")) {
//1. 获取到类名
String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//2. 获取类的完整的路径(全类名)
//path.replace("/",".") => com.lzw.spring.component.
String classFullName = path.replace("/", ".") + "." + className;
//3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
try {
Class<?> aClazz = classLoader.loadClass(classFullName);
if(aClazz.isAnnotationPresent(Component.class)){
//如果该类使用了@Component,说明是Spring bean
System.out.println("是一个Spring bean = " + aClazz + " 类名=" + className);
//先得到beanName
//1.得到Component注解
Component componentAnnotation = aClazz.getDeclaredAnnotation(Component.class);
//2.得到配置value的值
String beanName = componentAnnotation.value();
if("".equals(beanName)){//如果没有写value
//将该类的类名首字母小写,作为beanName
beanName = StringUtils.uncapitalize(className);
}
//3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(aClazz);
//4.获取Scope值
if(aClazz.isAnnotationPresent(Scope.class)){
//如果配置了Scope,获取配置的值
Scope scopeAnnotation = aClazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotation.value());
}else {
//如果没有配置,就用默认值singleton
beanDefinition.setScope("singleton");
}
//将beanDefinition放入到Map
beanDefinitionMap.put(beanName, beanDefinition);
}else{
//如果该类没有使用了@Component,说明不是Spring bean
System.out.println("不是一个Spring bean = " + aClazz+ " 类名=" + className);
}
}catch (Exception e){
}
}
}
System.out.println("==============================");
}
}
//返回容器中对象
public Object getBean(String name){
return null;
}
}
运行结果

阶段3-初始化 bean 单例池,并完成 getBean 方法 , createBean 方法
分析

代码实现
初始化单例池,并完成createBean方法
修改LzwSpringApplicationContext
package com.lzw.spring.ioc;
import com.lzw.spring.annotation.Component;
import com.lzw.spring.annotation.ComponentScan;
import com.lzw.spring.annotation.Scope;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author LiAng
* LzwSpringApplicationContext 类的作用类似Spring原生ioc容器
*/
public class LzwSpringApplicationContext {
private Class configClass;
//定义属性BeanDefinitionMap -> 存放BeanDefinition对象
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
//定义属性SingletonObjects -> 存放单例对象
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
public LzwSpringApplicationContext(Class configClass) {
//完成扫描指定的包
beanDefinitionByScan(configClass);
//通过beanDefinitionMap 初始化singletonObjects 单例池
//遍历所有的beanDefinition对象
Enumeration<String> keys = beanDefinitionMap.keys();
while (keys.hasMoreElements()){
//得到beanName
String beanName = keys.nextElement();
//通过beanName得到对应的 beanDefinition对象
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//判断该bean是singleton还是prototype
if("singleton".equalsIgnoreCase(beanDefinition.getScope())){
//将该bean实例放入到singletonObjects 集合
Object bean = createBean(beanDefinition);
singletonObjects.put(beanName,bean);
}
}
System.out.println("singletonObjects = " + singletonObjects);
System.out.println("beanDefinitionMap = " + beanDefinitionMap);
}
//该方法完成对指定包的扫描,并将Bean信息封装到BeanDefinition,再放入到Map
public void beanDefinitionByScan(Class configClass){
this.configClass = configClass;
//获取要扫描的包
//1. 先得到LzwSpringConfig配置的的@ComponentScan(value = "com.lzw.spring.component")
ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
//2. 通过componentScan的value=> 即要扫描的包
String path = componentScan.value();
System.out.println("要扫描的包 = " + path);
//得到要扫描的包下的所有资源(类 .class)
//1.得到类的加载器->APP 类加载器
ClassLoader classLoader = LzwSpringApplicationContext.class.getClassLoader();
//2. 通过类的加载器获取到要扫描的包的资源 url=》类似一个路径
path = path.replace(".", "/");
URL resource = classLoader.getResource(path);
System.out.println("resource=" + resource);
//3. 将要加载的资源(.class) 路径下的文件进行遍历=>io
File file = new File(resource.getFile());
if(file.isDirectory()){
File[] files = file.listFiles();
for (File f : files) {
//System.out.println("==========================");
//System.out.println("="+f.getAbsolutePath());
String fileAbsolutePath = f.getAbsolutePath();
//这里我们只处理.class文件
if (fileAbsolutePath.endsWith(".class")) {
//1. 获取到类名
String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//2. 获取类的完整的路径(全类名)
//path.replace("/",".") => com.lzw.spring.component.
String classFullName = path.replace("/", ".") + "." + className;
//3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
try {
Class<?> aClazz = classLoader.loadClass(classFullName);
if(aClazz.isAnnotationPresent(Component.class)){
//如果该类使用了@Component,说明是Spring bean
System.out.println("是一个Spring bean = " + aClazz + " 类名=" + className);
//先得到beanName
//1.得到Component注解
Component componentAnnotation = aClazz.getDeclaredAnnotation(Component.class);
//2.得到配置value的值
String beanName = componentAnnotation.value();
if("".equals(beanName)){//如果没有写value
//将该类的类名首字母小写,作为beanName
beanName = StringUtils.uncapitalize(className);
}
//3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(aClazz);
//4.获取Scope值
if(aClazz.isAnnotationPresent(Scope.class)){
//如果配置了Scope,获取配置的值
Scope scopeAnnotation = aClazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotation.value());
}else {
//如果没有配置,就用默认值singleton
beanDefinition.setScope("singleton");
}
//将beanDefinition放入到Map
beanDefinitionMap.put(beanName, beanDefinition);
}else{
//如果该类没有使用了@Component,说明不是Spring bean
System.out.println("不是一个Spring bean = " + aClazz+ " 类名=" + className);
}
}catch (Exception e){
}
}
}
System.out.println("==============================");
}
}
//完成createBean(BeanDefinition beanDefinition) 方法
//目前先简单实现
private Object createBean(BeanDefinition beanDefinition){
//得到Bean的clazz对象
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){
return null;
}
}

完成getBean方法
修改LzwSpringApplicationContext
编写getBean(String name)方法
//编写方法,返回容器中对象
public Object getBean(String name){
//加一个判断,确保传入的beanName是否存在beanDefinitionMap中
if(beanDefinitionMap.containsKey(name)) {//存在
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
//得到beanDefinition的scope,分别进行处理
if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
//说明是单例配置,就直接从单例池获取
return singletonObjects.get(name);
} else {//如果不是单例,就调用createBean,反射一个对象
return createBean(beanDefinition);
}
}else {//如果不存在
//抛出空指针异常
throw new NullPointerException("没有该bean");
}
}
运行结果

阶段4-完成实现依赖注入
分析

代码实现
创建注解 @Autowired
package com.lzw.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LiAng
*/
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}
修改MonsterDao
package com.lzw.spring.component;
import com.lzw.spring.annotation.Component;
/**
* @author LiAng
*/
@Component(value = "monsterDao")
public class MonsterDao {
public void hi(){
System.out.println("MonsterDao-hi()");
}
}
修改MonseterService
package com.lzw.spring.component;
import com.lzw.spring.annotation.Autowired;
import com.lzw.spring.annotation.Component;
import com.lzw.spring.annotation.Scope;
/**
* @author LiAng
* 说明MonsterService 是一个Service
* 1. 如果指定了value,那么在注入spring容器时,以你指定为准
* 2. 如果没有指定value ,则使用类名首字母小写为名字
*/
@Component//(value = "monsterService") //把MonsterService注入我们自己的spring容器中
@Scope(value = "prototype")
public class MonsterService {
//这里使用我们自己的@Autowired来修饰属性
//表示该属性,是通过容器完成依赖注入
//说明:实现按照名字来进行组装
@Autowired
private MonsterDao monsterDao;
public void m1(){
monsterDao.hi();
}
}
修改LzwSpringApplicationContext的createBean方法
//完成createBean(BeanDefinition beanDefinition) 方法
//目前先简单实现
private Object createBean(BeanDefinition beanDefinition){
//得到Bean的clazz对象
Class clazz = beanDefinition.getClazz();
try {
//使用反射实例
Object instance = clazz.getDeclaredConstructor().newInstance();
//分析:这里加入依赖注入的业务逻辑
//1.遍历当前要创建的对象的所有字段
for(Field declaredField:clazz.getDeclaredFields()){
//2.判断字段是否有 @Autowired
if(declaredField.isAnnotationPresent(Autowired.class)){
//3.得到字段的名字
String name = declaredField.getName();
//4.通过getBean方法来获取要组装的对象
Object bean = getBean(name);
//5.进行组装
declaredField.setAccessible(true);//因为属性是private,需要暴破
declaredField.set(instance,bean);
}
}
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//如果反射创建失败
return null;
}
package com.lzw.spring;
import com.lzw.spring.component.MonsterService;
import com.lzw.spring.ioc.LzwSpringApplicationContext;
import com.lzw.spring.ioc.LzwSpringConfig;
/**
* @author LiAng
*/
public class AppMain {
public static void main(String[] args) {
LzwSpringApplicationContext lzwSpringApplicationContext = new LzwSpringApplicationContext(LzwSpringConfig.class);
//测试一下依赖注入
MonsterService monsterService = (MonsterService)lzwSpringApplicationContext.getBean("monsterService");
monsterService.m1();
System.out.println("ok");
}
}
运行结果

阶段5-bean 后置处理器实现
分析

代码实现
创建接口 InitializingBean
package com.lzw.spring.process;
/**
* @author LiAng
* 1. 我们根据原生Spring 定义了一个InitializingBean
* 2. 该InitializingBean接口有一个方法
* 3. afterPropertiesSet() 在Bean的setter后执行,即就是我们原来的初始化方法
* 4. 当一个Bean实现这个接口后,就实现afterPropertiesSet(),这个方法就是初始化方法
*/
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
修改MonsterService
package com.lzw.spring.component;
import com.lzw.spring.annotation.Autowired;
import com.lzw.spring.annotation.Component;
import com.lzw.spring.annotation.Scope;
import com.lzw.spring.process.InitializingBean;
/**
* @author LiAng
* 说明MonsterService 是一个Service
* 1. 如果指定了value,那么在注入spring容器时,以你指定为准
* 2. 如果没有指定value ,则使用类名首字母小写为名字
*/
@Component//(value = "monsterService") //把MonsterService注入我们自己的spring容器中
@Scope(value = "prototype")
public class MonsterService implements InitializingBean {
//这里使用我们自己的@Autowired来修饰属性
//表示该属性,是通过容器完成依赖注入
//说明:实现按照名字来进行组装
@Autowired
private MonsterDao monsterDao;
public void m1(){
monsterDao.hi();
}
/**
* 1. afterPropertiesSet 就是在bean的setter方法执行完毕后被spring容器调用
* 2. 即就是初始化方法
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("monsterService 初始化方法被调用");
}
}
修改LzwSpringApplicationContext的createBean方法
在创建好 Bean 实例后,判断是否需要进行初始化 【容器中常 用的一个方法是,根据该类是否实现了某个接口,来判断是否要执行某个业务逻辑,这里其实就是 java 基础的接口编程实际运用】
private Object createBean(BeanDefinition beanDefinition){
//得到Bean的clazz对象
Class clazz = beanDefinition.getClazz();
try {
//使用反射实例
Object instance = clazz.getDeclaredConstructor().newInstance();
//分析:这里加入依赖注入的业务逻辑
//1.遍历当前要创建的对象的所有字段
for(Field declaredField:clazz.getDeclaredFields()){
//2.判断字段是否有 @Autowired
if(declaredField.isAnnotationPresent(Autowired.class)){
//提示
//处理@Autowired的required
//Autowired annotation = declaredField.getAnnotation(Autowired.class)
//annotation.required() => 然后进行其他处理
//3.得到字段的名字
String name = declaredField.getName();
//4.通过getBean方法来获取要组装的对象
Object bean = getBean(name);
//5.进行组装
declaredField.setAccessible(true);//因为属性是private,需要暴破
declaredField.set(instance,bean);
}
}
System.out.println("=============创建好实例========" + instance);
//这里判断是否要执行Bean的初始化方法
//1. 判断当前创建的Bean对象是否实现了 InitializingBean
//2. instanceof 表示判断某个对象的运行类型是不是某个类型或者某个类型的子类型
//3. 这里就是用到了接口编程
if(instance instanceof InitializingBean){
//3. 将instance 转成 InitializingBean
try {
((InitializingBean)instance).afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//如果反射创建失败
return null;
}
运行AppMain

创建接口 BeanPostProcessor
package com.lzw.spring.process;
/**
* @author LiAng
* 1. 参考原生Spring容器定义一个接口BeanPostProcessor
* 2. 该接口有两个方法postProcessBeforeInitialization 和 postProcessAfterInitialization
* 3. 这两个方法,会对Spring容器的所有Bean生效, 已经是切面编程的概念.
*/
public interface BeanPostProcessor {
/**
* postProcessBeforeInitialization在Bean的初始化方法前调用
* @param bean
* @param beanName
* @return
*/
default Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
/**
* postProcessAfterInitialization在Bean的初始化方法后调用
* @param bean
* @param beanName
* @return
*/
default Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
创建LzwBeanPostProcessor
package com.lzw.spring.component;
import com.lzw.spring.annotation.Component;
import com.lzw.spring.process.BeanPostProcessor;
/**
* @author LiAng
* 1. 这是我们自己的一个后置处理器
* 2. 实现了BeanPostProcessor
* 3. 我们可以重写before和after方法
* 4. 在Spring容器中,仍然把LzwBeanPostProcessor当做一个Bean对象,要再注入到容器
* 5. @Component 标识
* 6. 我们要让LzwBeanPostProcessor成为真正的后置处理器, 需要在容器中加入业务代码
* 7. 还要考虑多个后置处理器对象注入到容器问题
*/
@Component
public class LzwBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
//这里要体会到,后置处理器是会容器的创建的bean生效,相当于是可以对多个对象编程, 切面编程
//日志,权限,身份, 事务.......
System.out.println("后置处理器LzwBeanPostProcessor Before调用 bean类型=" + bean.getClass() + " bean的名字=" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("后置处理器LzwBeanPostProcessor After调用 bean类型=" + bean.getClass() + " bean的名字=" + beanName);
return bean;
}
}
修改LzwSpringApplicationContext
这里 createBean(String beanName, BeanDefinition beanDefinition) 需要增加入参数 beanName,就会导致 2个位置错误,需要根据错误提示,对应解决即可。
package com.lzw.spring.ioc;
import com.lzw.spring.annotation.Autowired;
import com.lzw.spring.annotation.Component;
import com.lzw.spring.annotation.ComponentScan;
import com.lzw.spring.annotation.Scope;
import com.lzw.spring.process.BeanPostProcessor;
import com.lzw.spring.process.InitializingBean;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author LiAng
* LzwSpringApplicationContext 类的作用类似Spring原生ioc容器
*/
public class LzwSpringApplicationContext {
private Class configClass;
//定义属性BeanDefinitionMap -> 存放BeanDefinition对象
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
//定义属性SingletonObjects -> 存放单例对象
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
//定义一个属性beanPostProcessorsList => 存放后置处理器
private List<BeanPostProcessor> beanPostProcessorsList = new ArrayList<>();
public LzwSpringApplicationContext(Class configClass) {
//完成扫描指定的包
beanDefinitionByScan(configClass);
//通过beanDefinitionMap 初始化singletonObjects 单例池
//遍历所有的beanDefinition对象
Enumeration<String> keys = beanDefinitionMap.keys();
while (keys.hasMoreElements()){
//得到beanName
String beanName = keys.nextElement();
//通过beanName得到对应的 beanDefinition对象
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//判断该bean是singleton还是prototype
if("singleton".equalsIgnoreCase(beanDefinition.getScope())){
//将该bean实例放入到singletonObjects 集合
Object bean = createBean(beanName,beanDefinition);
singletonObjects.put(beanName,bean);
}
}
//System.out.println("singletonObjects = " + singletonObjects);
//System.out.println("beanDefinitionMap = " + beanDefinitionMap);
}
//该方法完成对指定包的扫描,并将Bean信息封装到BeanDefinition,再放入到Map
public void beanDefinitionByScan(Class configClass){
this.configClass = configClass;
//获取要扫描的包
//1. 先得到LzwSpringConfig配置的的@ComponentScan(value = "com.lzw.spring.component")
ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
//2. 通过componentScan的value=> 即要扫描的包
String path = componentScan.value();
System.out.println("要扫描的包 = " + path);
//得到要扫描的包下的所有资源(类 .class)
//1.得到类的加载器->APP 类加载器
ClassLoader classLoader = LzwSpringApplicationContext.class.getClassLoader();
//2. 通过类的加载器获取到要扫描的包的资源 url=》类似一个路径
path = path.replace(".", "/");
URL resource = classLoader.getResource(path);
System.out.println("resource=" + resource);
//3. 将要加载的资源(.class) 路径下的文件进行遍历=>io
File file = new File(resource.getFile());
if(file.isDirectory()){
File[] files = file.listFiles();
for (File f : files) {
//System.out.println("==========================");
//System.out.println("="+f.getAbsolutePath());
String fileAbsolutePath = f.getAbsolutePath();
//这里我们只处理.class文件
if (fileAbsolutePath.endsWith(".class")) {
//1. 获取到类名
String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//2. 获取类的完整的路径(全类名)
//path.replace("/",".") => com.lzw.spring.component.
String classFullName = path.replace("/", ".") + "." + className;
//3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
try {
Class<?> clazz = classLoader.loadClass(classFullName);
if(clazz.isAnnotationPresent(Component.class)){
//如果该类使用了@Component,说明是Spring bean
System.out.println("是一个Spring bean = " + clazz + " 类名=" + className);
//说明:
//1. 为了方便,这里将后置处理器放入到一个 ArrayList
//2. 如果发现是一个后置处理器,就放入到 beanPostProcessorsList
//3. 在原生的Spring容器中,对后置处理器还是走的getBean,createBean
// ,但是需要在singletonObjects加入相应的业务逻辑
//4. 这里我们是为了学习后置处理器的机制
//判断当前的这个clazz有没有实现BeanPostProcessor
//说明, 这里我们不能使用 instanceof 来判断clazz是否实现了BeanPostProcessor
//原因: clazz不是一个实例对象,而是一个类对象/clazz, 使用isAssignableFrom
//将其当做一个语法理解
if(BeanPostProcessor.class.isAssignableFrom(clazz)){
BeanPostProcessor beanPostProcessor = (BeanPostProcessor)clazz.newInstance();
//放入到 beanPostProcessorsList
beanPostProcessorsList.add(beanPostProcessor);
continue;
}
//先得到beanName
//1.得到Component注解
Component componentAnnotation = clazz.getDeclaredAnnotation(Component.class);
//2.得到配置value的值
String beanName = componentAnnotation.value();
if("".equals(beanName)){//如果没有写value
//将该类的类名首字母小写,作为beanName
beanName = StringUtils.uncapitalize(className);
}
//3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
//4.获取Scope值
if(clazz.isAnnotationPresent(Scope.class)){
//如果配置了Scope,获取配置的值
Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotation.value());
}else {
//如果没有配置,就用默认值singleton
beanDefinition.setScope("singleton");
}
//将beanDefinition放入到Map
beanDefinitionMap.put(beanName, beanDefinition);
}else{
//如果该类没有使用了@Component,说明不是Spring bean
System.out.println("不是一个Spring bean = " + clazz+ " 类名=" + className);
}
}catch (Exception e){
}
}
}
System.out.println("==============================");
}
}
//完成createBean(BeanDefinition beanDefinition) 方法
//目前先简单实现
private Object createBean(String beanName, BeanDefinition beanDefinition){
//得到Bean的clazz对象
Class clazz = beanDefinition.getClazz();
try {
//使用反射实例
Object instance = clazz.getDeclaredConstructor().newInstance();
//分析:这里加入依赖注入的业务逻辑
//1.遍历当前要创建的对象的所有字段
for(Field declaredField:clazz.getDeclaredFields()){
//2.判断字段是否有 @Autowired
if(declaredField.isAnnotationPresent(Autowired.class)){
//提示
//处理@Autowired的required
//Autowired annotation = declaredField.getAnnotation(Autowired.class)
//annotation.required() => 然后进行其他处理
//3.得到字段的名字
String name = declaredField.getName();
//4.通过getBean方法来获取要组装的对象
Object bean = getBean(name);
//5.进行组装
declaredField.setAccessible(true);//因为属性是private,需要暴破
declaredField.set(instance,bean);
}
}
System.out.println("=============创建好实例========" + instance);
//我们在Bean的初始化方法前,调用后置处理器的before方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorsList) {
//在后置处理器的before方法,可以对容器的bean实例进行处理
//然后返回处理后的bean实例, 相当于做一个前置处理
Object current = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
if(current != null){
instance = current;
}
}
//这里判断是否要执行Bean的初始化方法
//1. 判断当前创建的Bean对象是否实现了 InitializingBean
//2. instanceof 表示判断某个对象的运行类型是不是某个类型或者某个类型的子类型
//3. 这里就是用到了接口编程
if(instance instanceof InitializingBean){
//3. 将instance 转成 InitializingBean
try {
((InitializingBean)instance).afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
}
//我们在Bean的初始化方法后,调用后置处理器的after方法
//我们在Bean的初始化方法后,调用后置处理器的after方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorsList) {
//在后置处理器的after方法,可以对容器的bean实例进行处理
//然后返回处理后的bean实例, 相当于做一个后置处理
//原生Spring容器,比这个还要复杂
Object current = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
if(current != null){
instance = current;
}
}
System.out.println("--------------------------------------");
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是否存在beanDefinitionMap中
if(beanDefinitionMap.containsKey(name)) {//存在
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
//得到beanDefinition的scope,分别进行处理
if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
//说明是单例配置,就直接从单例池获取
return singletonObjects.get(name);
} else {//如果不是单例,就调用createBean,反射一个对象
return createBean(name,beanDefinition);
}
}else {//如果不存在
//抛出空指针异常
throw new NullPointerException("没有该bean");
}
}
}
运行AppMain
package com.lzw.spring;
import com.lzw.spring.component.MonsterService;
import com.lzw.spring.ioc.LzwSpringApplicationContext;
import com.lzw.spring.ioc.LzwSpringConfig;
/**
* @author LiAng
*/
public class AppMain {
public static void main(String[] args) {
//创建自己的容器
LzwSpringApplicationContext lzwSpringApplicationContext = new LzwSpringApplicationContext(LzwSpringConfig.class);
//测试一下依赖注入
MonsterService monsterService = (MonsterService)lzwSpringApplicationContext.getBean("monsterService");
monsterService.m1();
System.out.println("ok");
}
}
运行结果

阶段6-AOP机制实现
分析

代码实现
创建接口 SmartAnimalable
package com.lzw.spring.component;
/**
* @author LiAng
*/
public interface SmartAnimalable {
float getSum(float i, float j);
float getSub(float i, float j);
}
创建SmartDog
package com.lzw.spring.component;
import com.lzw.spring.annotation.Component;
/**
* @author LiAng
* 实现接口是为了方便返回代理对象
*/
@Component(value = "smartDog")
public class SmartDog implements SmartAnimalable {
@Override
public float getSum(float i, float j) {
float res = i + j;
System.out.println("SmartDog-getSum-res=" + res);
return res;
}
@Override
public float getSub(float i, float j) {
float res = i - j;
System.out.println("SmartDog-getSub-res=" + res);
return res;
}
}
创建SmartAnimalAspect
package com.lzw.spring.component;
/**
* @author LiAng
* SmartAnimalAspect 当做一个切面类来使用
* 后面再分析如何做的更加灵活
*/
public class SmartAnimalAspect {
public static void showBeginLog(){
System.out.println("前置通知..");
}
public static void showSuccessLog(){
System.out.println("返回通知..");
}
}
修改LzwBeanPostProcessor
package com.lzw.spring.component;
import com.lzw.spring.annotation.Component;
import com.lzw.spring.process.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author LiAng
*/
@Component
public class LzwBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
//这里要体会到,后置处理器是会容器的创建的bean生效,相当于是可以对多个对象编程, 切面编程
//日志,权限,身份, 事务.......
System.out.println("后置处理器LzwBeanPostProcessor Before调用 bean类型=" + bean.getClass() + " bean的名字=" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("后置处理器LzwBeanPostProcessor After调用 bean类型=" + bean.getClass() + " bean的名字=" + beanName);
//实现AOP,返回代理对象,即对bean进行包装
//1. 先死后活 -> 后面通过注解就可以更加灵活
if("smartDog".equals(beanName)){
//使用JDK的动态代理,返回bean的代理对象
Object proxyInstance = Proxy.newProxyInstance(LzwBeanPostProcessor.class.getClassLoader(),
bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method=" + method.getName());
Object result = null;
//假如我们进行前置通知处理的方法是getSum
//后面通过注解就可以更加灵活
if("getSum".equals(method.getName())){
SmartAnimalAspect.showBeginLog();
result = method.invoke(bean, args);//执行目标方法
//进行返回通知的处理
SmartAnimalAspect.showSuccessLog();
}else{
result = method.invoke(bean, args);
}
return result;
}
});
//如果bean是需要返回代理对象的,这里就直接return proxyInstance
return proxyInstance;
}
//如果不需要AOP,返回 bean
return bean;
}
}
修改AppMain,并测试
package com.lzw.spring;
import com.lzw.spring.component.MonsterService;
import com.lzw.spring.component.SmartAnimalable;
import com.lzw.spring.ioc.LzwSpringApplicationContext;
import com.lzw.spring.ioc.LzwSpringConfig;
/**
* @author LiAng
*/
public class AppMain {
public static void main(String[] args) {
//创建自己的容器
LzwSpringApplicationContext lzwSpringApplicationContext = new LzwSpringApplicationContext(LzwSpringConfig.class);
//测试一下依赖注入
MonsterService monsterService = (MonsterService)lzwSpringApplicationContext.getBean("monsterService");
monsterService.m1();
//测试一下AOP机制是否生效
SmartAnimalable smartDog = (SmartAnimalable)lzwSpringApplicationContext.getBean("smartDog");
System.out.println("smartDog = " + smartDog.getClass());
smartDog.getSum(10,2);
System.out.println("ok");
}
}

把AOP做的更加灵活
核心知识点:注解+数据结构/map/少许算法+业务处理。
这里是个精简版模拟。
创建注解 @Aspect
package com.lzw.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LiAng
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
String value() default "";
}
创建注解 @Before
package com.lzw.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LiAng
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {
String value();
String argNames() default "";
}
创建注解 @AfterReturing
package com.lzw.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author LiAng
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterReturning {
String value();
String pointcut() default "";
String returning() default "";
String argNames() default "";
}
修改SmartAnimalAspect
package com.lzw.spring.component;
import com.lzw.spring.annotation.*;
/**
* @author LiAng
* SmartAnimalAspect 当做一个切面类来使用
*/
@Aspect //自己定义的注解
@Component //之前实现过的
public class SmartAnimalAspect {
@Before(value = "execution com.lzw.spring.component.SmartDog getSum")
public static void showBeginLog(){
System.out.println("前置通知..");
}
@AfterReturning(value = "execution com.lzw.spring.component.SmartDog getSum")
public static void showSuccessLog(){
System.out.println("返回通知..");
}
}
创建LzwTest测试
package com.lzw.spring;
import com.lzw.spring.annotation.AfterReturning;
import com.lzw.spring.annotation.Before;
import com.lzw.spring.component.SmartAnimalAspect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author LiAng
*/
public class LzwTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1. 获取SmartAnimalAspect的class对象
Class<SmartAnimalAspect> smartAnimalAspectClass = SmartAnimalAspect.class;
//2. 遍历该类的所有方法
for (Method declaredMethod : smartAnimalAspectClass.getDeclaredMethods()) {
//如果切面类的方法有Before注解
if (declaredMethod.isAnnotationPresent(Before.class)) {
//得到切面类的切入方法名
System.out.println("m:= " + declaredMethod.getName());
//得到Before(value="xxxx")
//得到Before注解
Before annotation = declaredMethod.getAnnotation(Before.class);
//得到Before注解的value
System.out.println("value:= " + annotation.value());
//得到切入要执行的方法.[反射基础]
Method declaredMethod1 = smartAnimalAspectClass.getDeclaredMethod(declaredMethod.getName());
//调用切入方法[通过反射调用]
declaredMethod1.invoke(smartAnimalAspectClass.newInstance(), null);
} else if (declaredMethod.isAnnotationPresent(AfterReturning.class)) {
//如果发现切面类有AfterReturning注解,同样可以进行处理..
System.out.println("m:= " + declaredMethod.getName());
AfterReturning annotation = declaredMethod.getAnnotation(AfterReturning.class);
System.out.println("value:= " + annotation.value());
//得到切入要执行的方法.
Method declaredMethod1 = smartAnimalAspectClass.getDeclaredMethod(declaredMethod.getName());
//调用切入方法[反射调用]
declaredMethod1.invoke(smartAnimalAspectClass.newInstance(), null);
}
}
}
}
运行结果
