回到目录:
OrangeZh:拉勾教育:JAVA高薪训练营 学习笔记zhuanlan.zhihu.com![a36fdbe43eed9315d0ae3589dff6be49.png](https://i-blog.csdnimg.cn/blog_migrate/a4a7e882eb32063717a39b5ce7e2bf81.png)
介绍
自定义IOC容器和AOP框架
实现简单的Spring的Ioc容器,包含容器初始化,Bean实例化,实现@Service、@Autowired、@Transactional、@Bean、@Value等注解
什么是IOC
IoC Inversion of Control (控制反转/反转控制),它是⼀个技术思想,不是⼀个技术实现
描述的事情:Java开发领域对象的创建,管理的问题
传统开发⽅式:⽐如类A依赖于类B,往往会在类A中new⼀个B的对象
IoC思想下开发⽅式:我们不⽤⾃⼰去new对象了,⽽是由IoC容器(Spring框架)去帮助我们实例化对象并且管理它,我们需要使⽤哪个对象,去问IoC容器要即可
我们丧失了⼀个权利(创建、管理对象的权利),得到了⼀个福利(不⽤考虑对象的创建、管理等⼀系列事情)
为什么叫做控制反转?
控制:指的是对象创建(实例化、管理)的权利
反转:控制权交给外部环境了(spring框架、IoC容器)
IoC解决对象之间的耦合问题
IOC和DI描述的是同⼀件事情,只不过⻆度不⼀样
![8c26c7ad005be3950da479219f5afad2.png](https://i-blog.csdnimg.cn/blog_migrate/3ac54e39d57291de5259f081f2cb1afe.jpeg)
什么是AOP
AOP: Aspect oriented Programming ⾯向切⾯编程/⾯向⽅⾯编程
AOP是OOP的延续,从OOP说起
OOP三⼤特征:封装、继承和多态
OOP是⼀种垂直继承体系,而AOP是一种纵向的体系
比如:想在多个业务方法运行前后记录日志,为了不影响业务代码那么就抽象出一个横切逻辑单读维护
手写实现IOC和AOP
案例实现了IOC容器的管理,包含容器初始化,Bean实例化,实现@Service、@Autowired、@Transactional、@Bean、@Value等注解,其中@Transactional就属于AOP的一种实现(动态代理)
- 导入必要的依赖包
<dependencies>
<!-- 单元测试Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- mysql数据库驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jackson依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
<!--dom4j依赖-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!--xpath表达式依赖-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<!--引入cglib依赖包-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_2</version>
</dependency>
</dependencies>
- 创建数据库外部配置文件 jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ozdemo?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
- 创建数据库表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for account
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
`aid` int(11) NOT NULL AUTO_INCREMENT,
`cardNo` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`money` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`aid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES (1, '6029621011001', '韩梅梅', 10000);
INSERT INTO `account` VALUES (2, '6029621011000', '李大雷', 10000);
SET FOREIGN_KEY_CHECKS = 1;
- 创建必要的注解类 @Service、@Autowired、@Transactional、@Bean、@Value、@Component等
@Transactional示例:其它类似
/**
* @Description: @Transactional注解
* @Author: Created by OrangeZh
* @Date: Created in 2020/9/4 17:37
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
String value() default "";
String transactionManager() default "";
}
- (AOP关建代码)创建动态代理工厂类 ProxyFactory和事务类 TransactionManager
/**
* 代理对象工厂:生成代理对象的
*/
@Component("proxyFactory")
public class ProxyFactory {
@Autowired
private TransactionManager transactionManager;
/**
* Jdk动态代理
*
* @param obj 委托对象
* @return 代理对象
*/
public Object getJdkProxy(Object obj) {
// 获取代理对象
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
// 开启事务(关闭事务的自动提交)
transactionManager.beginTransaction();
result = method.invoke(obj, args);
// 提交事务
transactionManager.commit();
} catch (Exception e) {
e.printStackTrace();
// 回滚事务
transactionManager.rollback();
// 抛出异常便于上层servlet捕获
throw e;
}
return result;
}
});
}
/**
* 使用cglib动态代理生成代理对象
*
* @param obj 委托对象
* @return
*/
public Object getCglibProxy(Object obj) {
return Enhancer.create(obj.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = null;
try {
// 开启事务(关闭事务的自动提交)
transactionManager.beginTransaction();
result = method.invoke(obj, objects);
// 提交事务
transactionManager.commit();
} catch (Exception e) {
e.printStackTrace();
// 回滚事务
transactionManager.rollback();
// 抛出异常便于上层servlet捕获
throw e;
}
return result;
}
});
}
}
/**
* 事务管理器类:负责手动事务的开启、提交、回滚
*/
@Component("transactionManager")
public class TransactionManager {
@Autowired
private ConnectionUtils connectionUtils;
// 开启手动事务控制
public void beginTransaction() throws SQLException {
connectionUtils.getCurrentThreadConn().setAutoCommit(false);
}
// 提交事务
public void commit() throws SQLException {
connectionUtils.getCurrentThreadConn().commit();
}
// 回滚事务
public void rollback() throws SQLException {
connectionUtils.getCurrentThreadConn().rollback();
}
}
- (IOC关建代码)创建BeanFactory IOC容器 bean工厂
/**
* @Description: IOC容器 bean工厂
* @Author: Created by OrangeZh
* @Date: Created in 2020/9/4 15:15
*/
public class BeanFactory {
//外部配置文件配置信息
private static Properties properties = new Properties();
private static final String classpath = BeanFactory.class.getResource("/").getPath();
//bean定义Map 处理存放bean的基本信息
private static Map<String, Class<?>> beanDefinitionMap = new ConcurrentHashMap<>();
//缓存bean 容器缓存(单例缓存池)
private static ConcurrentHashMap<String, Object> beanMap = new ConcurrentHashMap<>();
//扫描到的所有类
private static List<Class<?>> classList = new ArrayList<>();
static {
initIoc();
}
/**
* 初始化容器
* 1、获取配置文件配置内容
* 2、配置类(AppConfig)解析
* 3、扫描包下的所有类
* 4、遍历所有类,并放入到beanDefinitionMap中
* 5、实例化并初始化所有bean
*/
private static void initIoc() {
try {
//1、获取配置文件配置内容
properties = getProperties("jdbc.properties");
//2、配置类解析
Class<?> configClass = AppConfig.class;
String configBeanName = Introspector.decapitalize(configClass.getSimpleName());
beanDefinitionMap.put(configBeanName, configClass);
String[] scanPackages = configClass.getAnnotation(ComponentScan.class).value();
//3、加载包下的所有类
if (scanPackages.length > 0) {
for (String scanPackage : scanPackages) {
getAllClasses(scanPackage, classList);
}
} else {
getAllClasses("", classList);
}
//4、遍历所有类,并放入到beanDefinitionMap中
if (classList.size() > 0) {
for (Class<?> clazz : classList) {
String beanName = Introspector.decapitalize(clazz.getSimpleName());
//类注解
if (clazz.isAnnotationPresent(Component.class)) {
Component annotation = clazz.getAnnotation(Component.class);
if (!annotation.value().equals("")) {
beanName = annotation.value();
} else if (clazz.getInterfaces().length > 0) {
beanName = Introspector.decapitalize(clazz.getInterfaces()[0].getSimpleName());
}
} else if (clazz.isAnnotationPresent(Service.class)) {
Service annotation = clazz.getAnnotation(Service.class);
if (!annotation.value().equals("")) {
beanName = annotation.value();
} else if (clazz.getInterfaces().length > 0) {
beanName = Introspector.decapitalize(clazz.getInterfaces()[0].getSimpleName());
}
} else if (clazz.isAnnotationPresent(Repository.class)) {
Repository annotation = clazz.getAnnotation(Repository.class);
if (!annotation.value().equals("")) {
beanName = annotation.value();
}
} else {
continue;
}
beanDefinitionMap.put(beanName, clazz);
}
}
//5、实例化并初始化所有bean
//先初始化配置类
getBean(configBeanName);
for (String beanName : beanDefinitionMap.keySet()) {
getBean(beanName);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建bean
* 1、实例化Bean
* 2、初始化Bean
*
* @param beanName
* @throws Exception
*/
private static Object doCreateBean(String beanName) throws Exception {
Object bean = beanMap.get(beanName);
if (bean != null) {
return bean;
}
createBeanInstance(beanName);
populateBean(beanName);
return beanMap.get(beanName);
}
/**
* 实例化Bean
*
* @param beanName
* @throws Exception
*/
private static void createBeanInstance(String beanName) throws Exception {
Class<?> clazz = beanDefinitionMap.get(beanName);
//实例化
Object bean = clazz.newInstance();
if (clazz.isAnnotationPresent(Transactional.class)) {
//转为代理对象
ProxyFactory proxyFactory = (ProxyFactory) getBean("proxyFactory");
if (clazz.getInterfaces().length > 0) {
bean = proxyFactory.getJdkProxy(bean);//代理对象替换原对象
} else {
bean = proxyFactory.getCglibProxy(bean);//代理对象替换原对象
}
}
beanMap.put(beanName, bean);
}
/**
* 初始化Bean
* 解析 @Autowired、@Value、@Transactional等注解
*
* @param beanName
*/
private static void populateBean(String beanName) throws Exception {
Object bean = getBean(beanName);
Class<? extends Object> clazz = bean.getClass();
//自动注入
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
Annotation[] annotations = field.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation.annotationType().equals(Autowired.class)) {
//Autowired autowiredAnno = field.getAnnotation(Autowired.class);
//通过属性名称 获取bean
Object value = getBean(field.getName());
field.setAccessible(true);
//给属性赋值
field.set(bean, value);
} else if (annotation.annotationType().equals(Value.class)) {
Value valueAnno = field.getAnnotation(Value.class);
String value = valueAnno.value();
if (value.startsWith("${") && value.endsWith("}")) {
value = properties.getProperty(value.split("${")[1].split("}")[0]);
}
field.setAccessible(true);
//给属性赋值
field.set(bean, value);
}
}
}
//方法注解
Method[] methods = clazz.getMethods();
for (Method method : methods) {
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation.annotationType().equals(Transactional.class)) {
//转为代理对象
ProxyFactory proxyFactory = (ProxyFactory) getBean("proxyFactory");
Class<?>[] cl = clazz.getInterfaces();
if (clazz.getInterfaces().length > 0) {
bean = proxyFactory.getJdkProxy(bean);//代理对象替换原对象
} else {
bean = proxyFactory.getCglibProxy(bean);//代理对象替换原对象
}
beanMap.put(beanName, bean);
} else if (annotation.annotationType().equals(Bean.class)) {
Bean beanAnno = method.getAnnotation(Bean.class);
Class<?> returnClass = method.getReturnType();
String beanName1 = Introspector.decapitalize(returnClass.getSimpleName());
if (!beanAnno.value().equals("")) {
beanName1 = beanAnno.value();
}
//获取方法执行返回的对象,返回的就是bean
Object beanClass = method.invoke(bean);
beanMap.put(beanName1, beanClass);
}
}
}
}
/**
* 获取bean
*
* @param beanName
* @return
*/
public static Object getBean(String beanName) throws Exception {
Object bean = beanMap.get(beanName);
if (bean == null) {
bean = doCreateBean(beanName);
}
return bean;
}
/**
* 获取某个包下的所有类
*
* @param classes 存放类的list
* @param packageName 包名
* @return
*/
private static void getAllClasses(String packageName, List<Class<?>> classes) {
try {
//将包名转换为路径
String path = classpath + packageName.replaceAll(".", Matcher.quoteReplacement(File.separator));
File file = new File(path);
File[] fileList = file.listFiles();
if (null != fileList && fileList.length > 0) {
for (File curFile : fileList) {
if (curFile.isFile()) {
System.out.println("file is:" + curFile);
System.out.println(packageName + "." + curFile.getName().split(".")[0]);
Class<?> aClass = Class.forName(packageName + "." + curFile.getName().split(".")[0]);
classes.add(aClass);
}
if (curFile.isDirectory()) {
System.out.println("dir is :" + curFile);
getAllClasses(packageName + "." + curFile.getName(), classes);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 读取配置文件
*
* @return
*/
private static Properties getProperties(String... files) {
Properties properties = new Properties();
try {
if (files.length > 0) {
for (String file : files) {
InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
properties.load(inputStreamReader);
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Get properties is fail!");
}
return properties;
}
- 项目源码 https://gitee.com/orangezh/OZAnnoIocDemo
下一篇:
OrangeZh:Spring IOC应用及源码分析zhuanlan.zhihu.com回到目录:
OrangeZh:拉勾教育:JAVA高薪训练营 学习笔记zhuanlan.zhihu.com文章内容输出来源:拉勾教育 Java高薪训练营