新聞中心
Spring AOP 原理
什么是 AOP?
創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的松北網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
AOP 即面向切面編程,利用 AOP 可以對業(yè)務(wù)進(jìn)行解耦,提高重用性,提高開發(fā)效率
應(yīng)用場景:日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理
AOP 底層實(shí)現(xiàn)原理是采用代理實(shí)現(xiàn)的
Spring 事務(wù)
基本特性:
- 原子性
- 隔離性
- 一致性
- 持久性
事務(wù)控制分類:
編程式事務(wù):手動(dòng)控制事務(wù)操作
聲明式事務(wù):通過 AOP 控制事務(wù)
編程式事務(wù)實(shí)現(xiàn)
使用編程事務(wù)實(shí)現(xiàn)手動(dòng)事務(wù)
@Component
@Scope("prototype")
public class TransactionUtils {
// 獲取事務(wù)源
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
// 開啟事務(wù)
public TransactionStatus begin() {
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
return transaction;
}
// 提交事務(wù)
public void commit(TransactionStatus transaction) {
dataSourceTransactionManager.commit(transaction);
}
// 回滾事務(wù)
public void rollback(TransactionStatus transaction) {
dataSourceTransactionManager.rollback(transaction);
}
}
AOP技術(shù)封裝手動(dòng)事務(wù)
@Component
@Aspect
public class TransactionAop {
@Autowired
private TransactionUtils transactionUtils;
@Around("execution(* com.kernel.service.UserService.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) {
try {
// 調(diào)用方法之前執(zhí)行
System.out.println("開啟事務(wù)");
TransactionStatus transactionStatus = transactionUtils.begin();
proceedingJoinPoint.proceed();
System.out.println("提交事務(wù)");
transactionUtils.commit(transactionStatus);
} catch (Throwable throwable) {
System.out.println("回滾事務(wù)");
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
}
事務(wù)注意事項(xiàng):
一定不要將代碼通過 try 包裹起來,如果程序發(fā)生異常,事務(wù)接收不到異常,就會認(rèn)為程序正常執(zhí)行,就不會進(jìn)行回滾,必須手動(dòng)回滾
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
聲明式事務(wù)
通過 AOP 實(shí)現(xiàn),對方法進(jìn)行攔截,在方法執(zhí)行之前開啟事務(wù),結(jié)束后提交事務(wù),發(fā)生異?;貪L事務(wù)
自定義事務(wù)注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtTransaction {
}
事務(wù)實(shí)現(xiàn)
@Component
@Aspect
public class TransactionAop {
@Autowired
private TransactionUtils transactionUtils;
private TransactionStatus transactionStatus = null;
/**
* AOP實(shí)現(xiàn)事務(wù)管理
*
* @param proceedingJoinPoint 切面通知對象
*/
@Around("execution(* com.kernel.service.*.* (..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) {
try {
// 獲取注解對象
ExtTransaction extTransaction = getExtTransaction(proceedingJoinPoint);
begin(extTransaction);
// 執(zhí)行目標(biāo)方法
proceedingJoinPoint.proceed();
// 提交事務(wù)
commit();
} catch (Throwable throwable) {
transactionUtils.rollback();
}
}
/**
* 獲取注解對象
*
* @param proceedingJoinPoint 切面通知對象
* @return 注解對象
* @throws NoSuchMethodException
*/
public ExtTransaction getExtTransaction(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchMethodException {
// 獲取方法名稱
String method = proceedingJoinPoint.getSignature().getName();
// 獲取目標(biāo)方法
Class> classTarget = proceedingJoinPoint.getTarget().getClass();
// 獲取目標(biāo)對象類型
Class[] parameterTypes = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes();
// 獲取目標(biāo)對象方法
Method objMethod = classTarget.getMethod(method, parameterTypes);
// 獲取注解
ExtTransaction declaredAnnotation = objMethod.getDeclaredAnnotation(ExtTransaction.class);
return declaredAnnotation;
}
/**
* 開啟事務(wù)
* @param extTransaction 注解對象
* @return 事務(wù)對象
*/
TransactionStatus begin(ExtTransaction extTransaction) {
if (extTransaction != null)
transactionStatus = transactionUtils.begin();
return transactionStatus;
}
/**
* 提交事務(wù)
*/
void commit() {
if (transactionStatus != null)
transactionUtils.commit(transactionStatus);
}
/**
* 回滾事務(wù)
*/
void rollback() {
transactionUtils.rollback();
}
}
Spring事物傳播行為
- PROPAGATION_REQUIRED:如果當(dāng)前有事務(wù),就用當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)
- PROPAGATION_SUPPORTS:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行
- PROPAGATION_MANDATORY:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常
- PROPAGATION_REQUIRES_NEW:新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起
- PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起
- PROPAGATION_NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常
什么是 Spring IOC?
Spring IOC 指的是控制反轉(zhuǎn),IOC 容器負(fù)責(zé)實(shí)例化、定位、配置應(yīng)用程序中的對象及建立這些對象間的依賴,交由Spring來管理這些,實(shí)現(xiàn)解耦
手寫 Spring IOC
實(shí)現(xiàn)步驟:
掃包
將標(biāo)注了注解的類,通過反射創(chuàng)建實(shí)例并添加的 bean 容器中
當(dāng)用戶向容器要 bean 時(shí),通過 beanId 在 bean 容器中查找并返回實(shí)例
package com.kernel.ext;
import com.kernel.ext.annotation.ExtAutoWired;
import com.kernel.ext.annotation.ExtService;
import com.kernel.utils.ClassUtil;
import org.apache.commons.lang.StringUtils;
import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* IOC 注解版本
*/
public class ExtClassPathXmlApplicationContext {
// 包名
private String packageName;
// bean容器
private ConcurrentHashMap beans = null;
/**
* 構(gòu)造函數(shù)
*
* @param packageName 包名
* @throws InstantiationException
* @throws IllegalAccessException
*/
public ExtClassPathXmlApplicationContext(String packageName) throws InstantiationException, IllegalAccessException {
this.packageName = packageName;
init();
}
/**
* 初始化對象
*
* @throws IllegalAccessException
* @throws InstantiationException
*/
private void init() throws IllegalAccessException, InstantiationException {
// 遍歷所有類
List> classes = ClassUtil.getClasses(packageName);
// 將所有標(biāo)注ExtService注解的類加入到容器中
findAnnotationByClasses(classes);
}
/**
* 過濾標(biāo)注ExtService注解的類
*
* @param classes
* @throws InstantiationException
* @throws IllegalAccessException
*/
private void findAnnotationByClasses(List> classes) throws InstantiationException, IllegalAccessException {
for (Class classInfo : classes) {
ExtService extService = (ExtService) classInfo.getAnnotation(ExtService.class);
if (extService != null) {
Object newInstance = newInstance(classInfo);
beans.put(toLowerCaseFirstOne(classInfo.getSimpleName()), newInstance);
}
}
}
/**
* 通過反射構(gòu)建對象
*
* @param classInfo
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
private Object newInstance(Class classInfo) throws InstantiationException, IllegalAccessException {
return classInfo.getClass().newInstance();
}
/**
* 通過beanId查找對應(yīng)的實(shí)例
*
* @param beanId
* @return
*/
public Object getBean(String beanId) throws IllegalAccessException {
Object object = null;
if (StringUtils.isEmpty(beanId))
return null;
for (String id : beans.keySet())
if (beanId.equals(id)) {
object = beans.get(beanId);
attrAssign(object);
break;
}
return object;
}
/**
* 依賴注入
*/
void attrAssign(Object object) throws IllegalAccessException {
Class> aClass = object.getClass();
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
ExtAutoWired extAutoWired = field.getAnnotation(ExtAutoWired.class);
if (extAutoWired != null) {
field.setAccessible(true);
Object bean = getBean(field.getName());
field.set(field.getName(), object);
}
}
}
/**
* 首字母變小寫
*
* @param s
* @return
*/
public static String toLowerCaseFirstOne(String s) {
if (Character.isLowerCase(s.charAt(0)))
return s;
else {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(Character.toLowerCase(s.charAt(0)));
stringBuffer.append(s.substring(1));
return stringBuffer.toString();
}
}
}
Spring MVC 原理
執(zhí)行流程:
用戶請求 url 至前端控制器 DispatcherServlet
DispatcherServlet 調(diào)用處理器映射器 HandlerMapping
HandlerMapping 根據(jù) url 找到具體的處理器生成處理器執(zhí)行鏈,并將執(zhí)行鏈返回給 DispatcherServlet
DispatcherServlet 根據(jù)處理器 Handler 獲取處理器適配器 HandlerAdapter 執(zhí)行
執(zhí)行 Handler
返回 ModelAndView 返回給 DispatcherServlet
DispatcherServlet 將 ModelAnd view 傳遞給視圖解析器 ViewResolver
ViewResolver 解析成具體 View
渲染視圖
- 響應(yīng)頁面給用戶
Servlet 生命周期
init:在 Servlet 生命周期中,該方法僅執(zhí)行一次,它是在將服務(wù)器裝入 Servlet 時(shí)執(zhí)行的,負(fù)責(zé)初始化 Servlet 對象,Servlet 是單例多線程的
service:負(fù)責(zé)響應(yīng)請求,每當(dāng)一個(gè)客戶請求一個(gè) HttpServlet 對象,該對象的 Service 方法就要被調(diào)用,傳遞一個(gè) ServletRequest 和 ServletResponse 對象
destroy:在服務(wù)器停止卸載 Servlet 時(shí)調(diào)用
手寫 Spring MVC
實(shí)現(xiàn)步驟:
創(chuàng)建一個(gè) ExtDispatcherServlet 繼承 HttpServlet
掃包
將標(biāo)注了 @ExtController 注解的類,通過反射創(chuàng)建對象添加到容器中,將 beanId 和控制器關(guān)聯(lián)
將標(biāo)注了 @ExtRequestMapping 注解的類,將請求url 和控制器對象關(guān)聯(lián),將 url 和 方法關(guān)聯(lián)
當(dāng)用戶請求 url 時(shí),查找和 url 對應(yīng)的對象,然后查找和 url 對應(yīng)的方法,執(zhí)行方法,解析并渲染
package com.kernel.ext.servlet;
import com.kernel.controller.ExtIndexController;
import com.kernel.ext.annotation.ExtController;
import com.kernel.ext.annotation.ExtRequestMapping;
import com.kernel.utils.ClassUtil;
import org.apache.commons.lang.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* 手寫SpringMVC
*/
public class ExtDispatcherServlet extends HttpServlet {
// 關(guān)聯(lián)beanId和Object
private ConcurrentHashMap mvcBeans = new ConcurrentHashMap<>();
// 關(guān)聯(lián)url和控制器對象
private ConcurrentHashMap mvcBeanUrl = new ConcurrentHashMap<>();
// 關(guān)聯(lián)url和methodName
private ConcurrentHashMap mvcMethodUrl = new ConcurrentHashMap<>();
/**
* 初始化Servlet
*/
public void init() {
try {
List> classes = ClassUtil.getClasses("com.kernel.controller");
findClassMVCBeans(classes);
handlerMapping(mvcBeans);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 關(guān)聯(lián)url和控制器對象、url和methoName
* @param mvcBeans
*/
private void handlerMapping(ConcurrentHashMap mvcBeans) {
for (Object classInfo : mvcBeans.values()) {
ExtRequestMapping extCla***equestMapping = classInfo.getClass().getDeclaredAnnotation(ExtRequestMapping.class);
String requestBaseUrl = null;
if (extCla***equestMapping != null) {
requestBaseUrl = extCla***equestMapping.value();
}
Method[] methods = classInfo.getClass().getDeclaredMethods();
for (Method method : methods) {
ExtRequestMapping extMthodRequestMapping = method.getDeclaredAnnotation(ExtRequestMapping.class);
if (extCla***equestMapping != null){
String httpRequestUrl = extMthodRequestMapping.value();
mvcBeanUrl.put(requestBaseUrl + httpRequestUrl, classInfo);
mvcMethodUrl.put(requestBaseUrl + httpRequestUrl, method.getName());
}
}
}
}
/**
* 將所有控制器添加到mvcBeans中
* @param classes 包內(nèi)所有類
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
private void findClassMVCBeans(List> classes) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
for (Class classInfo : classes) {
ExtController extController = (ExtController) classInfo.getDeclaredAnnotation(ExtController.class);
if (extController != null){
mvcBeans.put(classInfo.getName(), ClassUtil.newInstance(classInfo));
}
}
}
/**
* get請求
* @param req
* @param resp
* @throws IOException
* @throws ServletException
*/
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
try {
doPost(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* post請求
* @param req
* @param resp
*/
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
try {
doDispatch(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 路由分發(fā)
* @param req
* @param resp
* @throws Exception
*/
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String requestUrl = req.getServletPath();
Object object = mvcBeanUrl.get(requestUrl);
if (object == null)
object = ExtIndexController.class.newInstance();
String methodName = mvcMethodUrl.get(requestUrl);
if (StringUtils.isEmpty(methodName))
methodName = "error";
Class> classInfo = object.getClass();
String resultPage = (String) methodInvoke(classInfo, object, methodName);
viewDisplay(resultPage, req, resp);
}
/**
* 視圖渲染
* @param resultPage
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
private void viewDisplay(String resultPage, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String suffix = ".jsp";
String prefix = "/";
req.getRequestDispatcher(prefix + resultPage + suffix).forward(req, resp);
}
/**
* 反射執(zhí)行方法
* @param classInfo 控制器
* @param object 控制器對象
* @param methodName 方法名稱
* @return
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws NoSuchMethodException
*/
private Object methodInvoke(Class> classInfo, Object object, String methodName) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Method method = null;
try {
method = classInfo.getDeclaredMethod(methodName);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
finally {
return method.invoke(object);
}
}
}
網(wǎng)頁題目:手寫Spring事務(wù)、IOC、DI和MVC
文章鏈接:http://www.dlmjj.cn/article/pdsscc.html