自动注解实现Spring IOC和事务管理的示例分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
IOC即控制反转,我们要把对象的创建通过注解来实现
@Service
类中声明了@Service注解的对象,我们就对它的实例化进行管理。(这里注解的名字无所谓,我们实现相应的功能即可)
@Autowired
类中的属性声明了@Autowired注解的,我们就对该属性进行依赖注入 在程序运行前,我们通过扫描所有的类文件,然后找出声明了@Service
注解的类,进行实例化,然后加入到我们的一个Map集合中,同时查找该类中是否有声明@Autowired
注解的属性,并进行标记。 再次遍历声明了@Service
注解的类,然后注入声明@Autowired
注解属性的类。这样我们就把对象的创建以及依赖的注入完成了。
事务管理需要我们遵循事务的ACID原则
@Transactional
类中或者方法中声明了@Transactional注解的我们就要对改对象或者方法添加事务控制功能 首先我们先扫描所有类文件,找出声明了@Transactional
注解的类或者方法,准备好一个List集合,如果注解声明在类上,我们就把类中所有的方法放入集合中,如果注解是在方法上,我们直接把方法加入到List集合中。 然后我们通过代理(动态代理或者cglib代理)给这些方法添加事务控制功能
public interface ApplicationContext {
Object getBean(String name);
<T> T getBean(String name, Class<T> requiredType);
}
这是一个核心配置类,主要实现了以下三个功能
获取所有配置了@Service注解的类,并实例化,放入Map中
对于类中添加@Autowired注解的属性进行依赖注入
对于添加了@Transactional注解的属性或者方法进行事务增强
public class AnnotationConfigApplicationContext implements ApplicationContext {
/**
* 存放bean
*/
private final Map<String, BeanDefinition> beanMap = new HashMap<>();
/**
* 先把包名转换为路径,首先得到项目的classpath
*/
private final String CLASSPATH = this.getClass().getResource("/").getPath();
public AnnotationConfigApplicationContext(String... basePackages) {
try {
scanPackages(basePackages);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 扫描所有包 并实现bean对象的创建,依赖注入,增强事务
* @param basePackages
* @throws ClassNotFoundException
* @throws InstantiationException
* @throws IllegalAccessException
*/
private void scanPackages(String[] basePackages) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
// 设置获取所有配置Service注解的对象
setBeanDefinition(basePackages);
// 设置依赖关系
setBeanDepend();
// 设置事务增强
setTransaction();
}
/**
* 获取所有需要管理的对象
*
* @param basePackages 需要扫描的包
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
private void setBeanDefinition(String[] basePackages) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 获取所有类路径下的class文件
List<String> classPaths = new ArrayList<>();
for (String basePackage : basePackages) {
//然后把我们的包名basPath转换为路径名
basePackage = basePackage.replace(".", File.separator);
//然后把classpath和basePack合并
String searchPath = CLASSPATH + basePackage;
getFile(classPaths, new File(searchPath));
}
// 找出所有有@Service注解的类,加入到beanMap中
for (String s : classPaths) {
s = s.replace(CLASSPATH, "").replace("/", ".").replace(".class", "");
Class clazz = Class.forName(s);
Service service = (Service) clazz.getAnnotation(Service.class);
if (service != null) {
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanObject(clazz.newInstance());
// 设置bean name
String value = service.value();
// 如果没有自定义bean name,设置bean name为class name
if ("".equals(value)) {
value = clazz.getName();
value = value.substring(value.lastIndexOf(".") + 1);
value = value.substring(0, 1).toLowerCase() + value.substring(1);
}
beanDefinition.setBeanName(value);
// 是否有依赖关系
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
Autowired autowired = declaredField.getAnnotation(Autowired.class);
// 如果类属性有@Autowired注解,把依赖对象放入BeanDefinition的dependBeanName集合中
if (autowired != null) {
beanDefinition.setAutoWired(true);
beanDefinition.getDependBeanName().add(declaredField.getName());
}
}
// 是否有父接口,为后面增强使用动态代理还是cglib代理做准备
Class[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
beanDefinition.setHaveParent(true);
}
// 是否有事务注解,如果有加入到BeanDefinition对象的transactionMethods属性中
Annotation annotation = clazz.getAnnotation(Transactional.class);
Method[] methods = clazz.getDeclaredMethods();
//如果@Transactional注解出现在类上面,把类下所有的方法都加入到待添加事务的列表中
if (annotation != null) {
for (Method method : methods) {
beanDefinition.getTransactionMethods().add(method);
}
} else {
// 如果@Transactional在某个方法上面,把该方法加入到BeanDefinition对象的transactionMethods属性中
for (Method method : methods) {
Transactional methodAnnotation = method.getAnnotation(Transactional.class);
if (methodAnnotation != null) {
beanDefinition.getTransactionMethods().add(method);
}
}
}
// 将添加事务之后的对象重新加入到beanMap中
beanMap.put(beanDefinition.getBeanName(), beanDefinition);
}
}
}
/**
* 遍历所有bean,找出有依赖关系的bean,注入
*/
private void setBeanDepend() {
for (Map.Entry<String, BeanDefinition> next : beanMap.entrySet()) {
BeanDefinition beanDefinition = next.getValue();
//如果有AutoWired注解,设置值
if (beanDefinition.isAutoWired()) {
Object object = beanDefinition.getBeanObject();
Class<?> definitionClass = object.getClass();
List<String> beanNames = beanDefinition.getDependBeanName();
beanNames.forEach(w -> {
try {
// 获取需要进行注入的对象
Field declaredField = definitionClass.getDeclaredField(w);
// 暴力访问
declaredField.setAccessible(true);
// 给依赖对象赋值
declaredField.set(object, getBean(w));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
});
// 组装好的对象重新放入map中
beanMap.put(beanDefinition.getBeanName(), beanDefinition);
}
}
}
/**
* 配置事务增强
*/
private void setTransaction() {
for (Map.Entry<String, BeanDefinition> next : beanMap.entrySet()) {
BeanDefinition definition = next.getValue();
//获取需要开启事务管理的类下的所有方法
List<Method> transactionMethods = definition.getTransactionMethods();
ProxyFactory proxyFactory = new ProxyFactory();
// 根据代理对象是实现接口,来决定采用动态代理还是cglib代理
if (!definition.isHaveParent()) {
proxyFactory = new ProxyFactory(new CglibProxy());
}
//给方法配置事务增强
Object withTransaction = proxyFactory.getProxyWithTransaction(definition.getBeanObject(), transactionMethods);
definition.setBeanObject(withTransaction);
//把增强之后的对象重新放入到beanMap中
beanMap.put(next.getKey(), definition);
}
}
private void getFile(List<String> classPaths, File file) {
//文件夹递归
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File f1 : files) {
getFile(classPaths, f1);
}
}
} else {
//标准文件获取class文件
if (file.getName().endsWith(Constant.FILE_TYPE_CLASS)) {
//如果是class文件我们就放入我们的集合中。
classPaths.add(file.getPath());
}
}
}
@Override
public Object getBean(String name) {
return beanMap.get(name).getBeanObject();
}
@Override
public <T> T getBean(String name, Class<T> requiredType) {
Object o = beanMap.get(name).getBeanObject();
if (o.getClass() == requiredType) {
return (T) o;
}
return null;
}
}
对于事务的增强,我们需要依赖代理来实现。代理我们使用了动态代理和cglib代理两种,对于需要代理对象实现接口的,我们使用动态代理;对于没有实现接口的对象,我们使用cglib代理。下面看下具体实现。
public interface AopProxy {
/**
* 创建带事务的代理
*
* @param o 代理对象
* @param methods 代理对象中需要添加事务的方法
* @return 增强之后的代理对象
*/
abstract Object createProxyWithTransaction(Object o, List<Method> methods);
}
public class DynamicProxy implements AopProxy {
@Override
public Object createProxyWithTransaction(Object o, List<Method> methods) {
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), (proxy, method, args) -> {
Object invoke = null;
boolean anyMatch = methods.stream().anyMatch(w -> w.getName().equals(method.getName()));
if (anyMatch) {
TransactionManager.getInstance().beginTransaction();
try {
invoke = method.invoke(o, args);
TransactionManager.getInstance().commit();
} catch (Exception e) {
TransactionManager.getInstance().rollback();
throw e;
}
return invoke;
}
invoke = method.invoke(o, args);
return invoke;
});
}
}
public class CglibProxy implements AopProxy {
@Override
public Object createProxyWithTransaction(Object o, List<Method> methods) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(o.getClass());
enhancer.setCallback((MethodInterceptor) (o1, method, objects, methodProxy) -> {
Object invoke;
boolean anyMatch = methods.stream().anyMatch(w -> w.getName().equals(method.getName()));
if (anyMatch) {
TransactionManager.getInstance().beginTransaction();
try {
invoke = method.invoke(o, objects);
TransactionManager.getInstance().commit();
} catch (Exception e) {
TransactionManager.getInstance().rollback();
throw e;
}
return invoke;
}
invoke = method.invoke(o, objects);
return invoke;
});
return enhancer.create();
}
}
看完上述内容,你们掌握自动注解实现Spring IOC和事务管理的示例分析的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4629149/blog/4605915