日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

aop 代码_项目学生:使用AOP简化代码

發(fā)布時(shí)間:2023/12/3 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 aop 代码_项目学生:使用AOP简化代码 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

aop 代碼

這是Project Student的一部分。

許多人堅(jiān)信方法應(yīng)適合您的編輯器窗口(例如20行),而有些人認(rèn)為方法應(yīng)小于此范圍。 這個(gè)想法是一種方法應(yīng)該做一件事,而只能做一件事。 如果它做的還不止于此,則應(yīng)將其分解為多種方法,而舊方法的“一件事”就是協(xié)調(diào)新方法。

這并不意味著在任意數(shù)量的行之后拆分一種方法。 有時(shí)方法自然會(huì)更大。 仍然是一個(gè)很好的問題。

那么,如何識(shí)別不只一件事的代碼? 一個(gè)好的試金石是代碼是否在多種方法中重復(fù)。 典型的例子是持久性類中的事務(wù)管理。 每個(gè)持久性類都需要它,并且代碼始終看起來相同。

另一個(gè)示例是Resource類中未處理的異常處理程序。 每個(gè)面向REST的方法都需要處理此問題,并且代碼始終看起來相同。

那是理論。 在實(shí)踐中,代碼可能很丑陋并且收益不大。 幸運(yùn)的是,有一個(gè)解決方案:面向方面的編程(AOP)。 這使我們可以在方法調(diào)用之前或之后透明地編織代碼。 這通常使我們可以大大簡(jiǎn)化我們的方法。

設(shè)計(jì)決策

AspectJ –我正在通過Spring注入來使用AspectJ。

局限性

使用CRUD方法,AspectJ切入點(diǎn)表達(dá)式相對(duì)簡(jiǎn)單。 當(dāng)添加了更復(fù)雜的功能時(shí),情況可能并非如此。

資源方法中未處理的異常

我們首先關(guān)心的是資源方法中未處理的異常。 不管怎樣,Jersey都會(huì)返回SERVER INTERNAL ERROR(服務(wù)器內(nèi)部錯(cuò)誤)(500)消息,但它可能包含堆棧跟蹤信息和我們不希望攻擊者知道的其他內(nèi)容。 如果我們自己發(fā)送它,我們可以控制它包含的內(nèi)容。 我們可以在所有方法中添加一個(gè)“ catch”塊,但可以將其復(fù)制到AOP方法中。 這將使我們所有的Resource方法更加苗條和易于閱讀。

此類還檢查“找不到對(duì)象”異常。 在單個(gè)Resource類中將很容易處理,但會(huì)使代碼混亂。 將異常處理程序放在此處可使我們的方法專注于快樂路徑并保證響應(yīng)的一致性。

該類有兩個(gè)優(yōu)化。 首先,它顯式檢查UnitTestException并在這種情況下跳過詳細(xì)的日志記錄。 我最大的煩惱之一就是當(dāng)一切都按預(yù)期方式運(yùn)行時(shí),使用堆棧跟蹤信息淹沒日志的測(cè)試。 這使得不可能針對(duì)明顯的問題瀏覽日志。 單個(gè)更改可以使問題更容易發(fā)現(xiàn)。

其次,它使用與目標(biāo)類(例如CourseResource)關(guān)聯(lián)的記錄器,而不是與AOP類關(guān)聯(lián)的記錄器。 除了更清晰之外,這還使我們可以有選擇地更改單個(gè)Resource(而不是全部)的日志記錄級(jí)別。

另一個(gè)技巧是在處理程序中調(diào)用ExceptionService 。 該服務(wù)可以對(duì)異常做一些有用的事情,例如,它可以創(chuàng)建或更新Jira票證。 這還沒有實(shí)現(xiàn),所以我只是發(fā)表評(píng)論以說明它的去向。

@Aspect @Component public class UnexpectedResourceExceptionHandler {@Around("target(com.invariantproperties.sandbox.student.webservice.server.rest.AbstractResource)")public Object checkForUnhandledException(ProceedingJoinPoint pjp) throws Throwable {Object results = null;Logger log = Logger.getLogger(pjp.getSignature().getClass());try {results = pjp.proceed(pjp.getArgs());} catch (ObjectNotFoundException e) {// this is safe to log since we know that we've passed filtering.String args = Arrays.toString(pjp.getArgs());results = Response.status(Status.NOT_FOUND).entity("object not found: " + args).build();if (log.isDebugEnabled()) {log.debug("object not found: " + args);}} catch (Exception e) {// find the method we called. We can't cache this since the method// may be overloadedMethod method = findMethod(pjp); if ((method != null) && Response.class.isAssignableFrom(method.getReturnType())) {// if the method returns a response we can return a 500 message.if (!(e instanceof UnitTestException)) {if (log.isInfoEnabled()) {log.info(String.format("%s(): unhandled exception: %s", pjp.getSignature().getName(),e.getMessage()), e);}} else if (log.isTraceEnabled()) {log.info("unit test exception: " + e.getMessage());}results = Response.status(Status.INTERNAL_SERVER_ERROR).build();} else {// DO NOT LOG THE EXCEPTION. That just clutters the log - let// the final handler log it.throw e;}}return results;}/*** Find method called via reflection.*/Method findMethod(ProceedingJoinPoint pjp) {Class[] argtypes = new Class[pjp.getArgs().length];for (int i = 0; i < argtypes.length; i++) {argtypes[i] = pjp.getArgs()[i].getClass();}Method method = null;try {// @SuppressWarnings("unchecked")method = pjp.getSignature().getDeclaringType().getMethod(pjp.getSignature().getName(), argtypes);} catch (Exception e) {Logger.getLogger(UnexpectedResourceExceptionHandler.class).info(String.format("could not find method for %s.%s", pjp.getSignature().getDeclaringType().getName(),pjp.getSignature().getName()));}return method;} }

REST發(fā)布值檢查

我們的Resource方法也有很多樣板代碼來檢查REST參數(shù)。 它們是否為非空,電子郵件地址的格式是否正確,等等。同樣,很容易將許多代碼移入AOP方法并簡(jiǎn)化Resource方法。

我們首先定義一個(gè)接口,該接口指示可以驗(yàn)證REST傳輸對(duì)象。 第一個(gè)版本使我們可以簡(jiǎn)單地接受或拒絕,改進(jìn)的版本將使我們有辦法告訴客戶具體問題是什么。

public interface Validatable {boolean validate(); }

現(xiàn)在,我們擴(kuò)展了先前的REST傳輸對(duì)象,以添加一種驗(yàn)證方法。

兩個(gè)筆記。 首先,名稱和電子郵件地址接受Unicode字母,而不僅僅是標(biāo)準(zhǔn)ASCII字母。 隨著我們的世界國際化,這一點(diǎn)很重要。

其次,我添加了一個(gè)toString()方法,但是由于它使用了未經(jīng)處理的值,因此它是不安全的。 我將在稍后處理消毒。

@XmlRootElement public class NameAndEmailAddressRTO implements Validatable {// names must be alphabetic, an apostrophe, a dash or a space. (Anne-Marie,// O'Brien). This pattern should accept non-Latin characters.// digits and colon are added to aid testing. Unlikely but possible in real// names.private static final Pattern NAME_PATTERN = Pattern.compile("^[\\p{L}\\p{Digit}' :-]+$");// email address must be well-formed. This pattern should accept non-Latin// characters.private static final Pattern EMAIL_PATTERN = Pattern.compile("^[^@]+@([\\p{L}\\p{Digit}-]+\\.)?[\\p{L}]+");private String name;private String emailAddress;private String testUuid;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getEmailAddress() {return emailAddress;}public void setEmailAddress(String emailAddress) {this.emailAddress = emailAddress;}public String getTestUuid() {return testUuid;}public void setTestUuid(String testUuid) {this.testUuid = testUuid;}/*** Validate values.*/@Overridepublic boolean validate() {if ((name == null) || !NAME_PATTERN.matcher(name).matches()) {return false;}if ((emailAddress == null) || !EMAIL_PATTERN.matcher(emailAddress).matches()) {return false;}if ((testUuid != null) && !StudentUtil.isPossibleUuid(testUuid)) {return false;}return true;}@Overridepublic String toString() {// FIXME: this is unsafe!return String.format("NameAndEmailAddress('%s', '%s', %s)", name, emailAddress, testUuid);} }

我們對(duì)其他REST傳輸對(duì)象進(jìn)行了類似的更改。

現(xiàn)在,我們可以編寫AOP方法來檢查CRUD操作的參數(shù)。 和以前一樣,使用與資源關(guān)聯(lián)的記錄器而不是AOP類來寫入日志。

這些方法還記錄Resource方法的條目。 同樣,它是樣板,在此進(jìn)行簡(jiǎn)化了Resource方法。 記錄該方法的退出和運(yùn)行時(shí)間也很簡(jiǎn)單,但是在這種情況下,我們應(yīng)該使用一個(gè)股票記錄器AOP類。

@Aspect @Component public class CheckPostValues {/*** Check post values on create method.* * @param pjp* @return* @throws Throwable*/@Around("target(com.invariantproperties.sandbox.student.webservice.server.rest.AbstractResource) && args(validatable,..)")public Object checkParametersCreate(ProceedingJoinPoint pjp, Validatable rto) throws Throwable {final Logger log = Logger.getLogger(pjp.getSignature().getDeclaringType());final String name = pjp.getSignature().getName();Object results = null;if (rto.validate()) {// this should be safe since parameters have been validated.if (log.isDebugEnabled()) {log.debug(String.format("%s(%s): entry", name, Arrays.toString(pjp.getArgs())));}results = pjp.proceed(pjp.getArgs());} else {// FIXME: this is unsafeif (log.isInfoEnabled()) {log.info(String.format("%s(%s): bad arguments", name, Arrays.toString(pjp.getArgs())));}// TODO: tell caller what the problems wereresults = Response.status(Status.BAD_REQUEST).build();}return results;}/*** Check post values on update method.* * @param pjp* @return* @throws Throwable*/@Around("target(com.invariantproperties.sandbox.student.webservice.server.rest.AbstractResource) && args(uuid,validatable,..)")public Object checkParametersUpdate(ProceedingJoinPoint pjp, String uuid, Validatable rto) throws Throwable {final Logger log = Logger.getLogger(pjp.getSignature().getDeclaringType());final String name = pjp.getSignature().getName();Object results = null;if (!StudentUtil.isPossibleUuid(uuid)) {// this is a possible attack.if (log.isInfoEnabled()) {log.info(String.format("%s(): uuid", name));}results = Response.status(Status.BAD_REQUEST).build();} else if (rto.validate()) {// this should be safe since parameters have been validated.if (log.isDebugEnabled()) {log.debug(String.format("%s(%s): entry", name, Arrays.toString(pjp.getArgs())));}results = pjp.proceed(pjp.getArgs());} else {// FIXME: this is unsafeif (log.isInfoEnabled()) {log.info(String.format("%s(%s): bad arguments", name, Arrays.toString(pjp.getArgs())));}// TODO: tell caller what the problems wereresults = Response.status(Status.BAD_REQUEST).build();}return results;}/*** Check post values on delete method. This is actually a no-op but it* allows us to log method entry.* * @param pjp* @return* @throws Throwable*/@Around("target(com.invariantproperties.sandbox.student.webservice.server.rest.AbstractResource) && args(uuid,version) && execution(* *.delete*(..))")public Object checkParametersDelete(ProceedingJoinPoint pjp, String uuid, Integer version) throws Throwable {final Logger log = Logger.getLogger(pjp.getSignature().getDeclaringType());final String name = pjp.getSignature().getName();Object results = null;if (!StudentUtil.isPossibleUuid(uuid)) {// this is a possible attack.if (log.isInfoEnabled()) {log.info(String.format("%s(): uuid", name));}results = Response.status(Status.BAD_REQUEST).build();} else {// this should be safe since parameters have been validated.if (log.isDebugEnabled()) {log.debug(String.format("%s(%s): entry", name, Arrays.toString(pjp.getArgs())));}results = pjp.proceed(pjp.getArgs());}return results;}/*** Check post values on find methods. This is actually a no-op but it allows* us to log method entry.* * @param pjp* @return* @throws Throwable*/@Around("target(com.invariantproperties.sandbox.student.webservice.server.rest.AbstractResource) && execution(* *.find*(..))")public Object checkParametersFind(ProceedingJoinPoint pjp) throws Throwable {final Logger log = Logger.getLogger(pjp.getSignature().getDeclaringType());if (log.isDebugEnabled()) {log.debug(String.format("%s(%s): entry", pjp.getSignature().getName(), Arrays.toString(pjp.getArgs())));}final Object results = pjp.proceed(pjp.getArgs());return results;} }

更新了Spring配置

我們必須告訴Spring搜索AOP類。 這是對(duì)我們的配置文件的單行更改。

<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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><aop:aspectj-autoproxy/> </beans>

更新資源

現(xiàn)在,我們可以簡(jiǎn)化資源類。 僅有幾種方法可以簡(jiǎn)化為幸福道路。

@Service @Path("/course") public class CourseResource extends AbstractResource {private static final Logger LOG = Logger.getLogger(CourseResource.class);private static final Course[] EMPTY_COURSE_ARRAY = new Course[0];@Resourceprivate CourseFinderService finder;@Resourceprivate CourseManagerService manager;@Resourceprivate TestRunService testRunService;/*** Default constructor.*/public CourseResource() {}/*** Set values used in unit tests. (Required due to AOP)* * @param finder* @param manager* @param testService*/void setServices(CourseFinderService finder, CourseManagerService manager, TestRunService testRunService) {this.finder = finder;this.manager = manager;this.testRunService = testRunService;}/*** Get all Courses.* * @return*/@GET@Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })public Response findAllCourses() {final List courses = finder.findAllCourses();final List results = new ArrayList(courses.size());for (Course course : courses) {results.add(scrubCourse(course));}final Response response = Response.ok(results.toArray(EMPTY_COURSE_ARRAY)).build();return response;}/*** Create a Course.* * FIXME: what about uniqueness violations?* * @param req* @return*/@POST@Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })@Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })public Response createCourse(CourseInfo req) {final String code = req.getCode();final String name = req.getName();Response response = null;Course course = null;if (req.getTestUuid() != null) {TestRun testRun = testRunService.findTestRunByUuid(req.getTestUuid());if (testRun != null) {course = manager.createCourseForTesting(code, name, req.getSummary(), req.getDescription(),req.getCreditHours(), testRun);} else {response = Response.status(Status.BAD_REQUEST).entity("unknown test UUID").build();}} else {course = manager.createCourse(code, name, req.getSummary(), req.getDescription(), req.getCreditHours());}if (course == null) {response = Response.status(Status.INTERNAL_SERVER_ERROR).build();} else {response = Response.created(URI.create(course.getUuid())).entity(scrubCourse(course)).build();}return response;}/*** Get a specific Course.* * @param uuid* @return*/@Path("/{courseId}")@GET@Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })public Response getCourse(@PathParam("courseId") String id) {// 'object not found' handled by AOPCourse course = finder.findCourseByUuid(id);final Response response = Response.ok(scrubCourse(course)).build();return response;}/*** Update a Course.* * FIXME: what about uniqueness violations?* * @param id* @param req* @return*/@Path("/{courseId}")@POST@Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })@Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })public Response updateCourse(@PathParam("courseId") String id, CourseInfo req) {final String name = req.getName();// 'object not found' handled by AOPfinal Course course = finder.findCourseByUuid(id);final Course updatedCourse = manager.updateCourse(course, name, req.getSummary(), req.getDescription(),req.getCreditHours());final Response response = Response.ok(scrubCourse(updatedCourse)).build();return response;}/*** Delete a Course.* * @param id* @return*/@Path("/{courseId}")@DELETEpublic Response deleteCourse(@PathParam("courseId") String id, @PathParam("version") Integer version) {// we don't use AOP handler since it's okay for there to be no matchtry {manager.deleteCourse(id, version);} catch (ObjectNotFoundException exception) {LOG.debug("course not found: " + id);}final Response response = Response.noContent().build();return response;} }

單元測(cè)試

單元測(cè)試需要對(duì)每個(gè)測(cè)試進(jìn)行更改,因?yàn)槲覀儾荒芎?jiǎn)單地實(shí)例化被測(cè)試的對(duì)象–我們必須使用Spring,以便正確編織AOP類。 幸運(yùn)的是,這實(shí)際上是唯一的更改–我們檢索資源并通過package-private方法而不是package-private構(gòu)造函數(shù)設(shè)置服務(wù)。

我們還需要為服務(wù)bean創(chuàng)建Spring值。 配置器類負(fù)責(zé)此工作。

@Configuration @ComponentScan(basePackages = { "com.invariantproperties.sandbox.student.webservice.server.rest" }) @ImportResource({ "classpath:applicationContext-rest.xml" }) // @PropertySource("classpath:application.properties") public class TestRestApplicationContext1 {@Beanpublic CourseFinderService courseFinderService() {return null;}@Beanpublic CourseManagerService courseManagerService() {return null;}....

整合測(cè)試

集成測(cè)試不需要任何更改。

源代碼

  • 源代碼位于https://github.com/beargiles/project-student [github]和http://beargiles.github.io/project-student/ [github頁面]。

參考: 項(xiàng)目學(xué)生:來自Invariant Properties博客的JCG合作伙伴 Bear Giles 使用AOP簡(jiǎn)化代碼 。

翻譯自: https://www.javacodegeeks.com/2014/01/project-student-simplifying-code-with-aop.html

aop 代碼

總結(jié)

以上是生活随笔為你收集整理的aop 代码_项目学生:使用AOP简化代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。