AOP(Aspect Oriented Programming)的縮寫,面向切面編程,主要作用就是對代碼進行增強處理。
理解面向切面編程的含義:就是在不改變原有程序的基礎上為代碼增加新的功能。
實現面向切面編程需要了解兩個概念:
>切入點:可以插入增強處理的方法,比如原對象的fun()方法。
>增強處理類型:在原對象fun()方法之前還是之後插入新功能。
1.新建一個java項目
2.到官網下載Spring AOP和AspectJ框架所需要的jar包,並將下載所需的jar文件添加到項目中。
3.在項目中添加User實體類
package com.jbit.fsd.entity; public class User { private int id; private String username; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
4.添加數據訪問層接口和實現類,並添加相應的方法
package com.jbit.fsd.dao; import java.util.List; import com.jbit.fsd.entity.User; // 數據訪問層接口 public interface UserDao { public List<User> getAll(); public void addUser(User user); }
實現類:
package com.jbit.fsd.dao.impl; import java.util.ArrayList; import java.util.List; import com.jbit.fsd.dao.UserDao; import com.jbit.fsd.entity.User; public class UserDaoImpl implements UserDao { @Override public List<User> getAll() { //操作數據庫讀到所有數據 List<User> list=new ArrayList<User>(); list.add(new User()); list.add(new User()); list.add(new User()); return list; } @Override public void addUser(User user) { System.out.println("添加成功"); } }
5.添加業務處理層接口和實現類
package com.jbit.fsd.service; import java.util.List; import com.jbit.fsd.dao.UserDao; import com.jbit.fsd.entity.User; public interface UserService { public List<User> getAll(); public void addUser(User user); }
實現類:
package com.jbit.fsd.service.impl; import java.util.List; import com.jbit.fsd.dao.UserDao; import com.jbit.fsd.entity.User; import com.jbit.fsd.service.UserService; public class UserServiceImpl implements UserService{ private UserDao dao; //通過spring注入進來 public void setDao(UserDao dao) { this.dao = dao; } @Override public List<User> getAll() { System.out.println("正在執行添加用戶的業務!"); return dao.getAll(); } @Override public void addUser(User user) {
System.out.println("正在執行添加用戶的業務!"); dao.addUser(user); } }
6.添加AOP增強處理類
package com.jbit.fsd.aop; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ServiceLoging { private Log log = LogFactory.getLog(this.getClass()); public void beforeService(){ log.info("aop方法被調用!"); } }
7.在src目錄下新建applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!-- - Application context definition for JPetStore's business layer. - Contains bean references to the transaction manager and to the DAOs in - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation"). --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- 以面向接口思想編程實現解耦和 --> <bean id="userDao" class="com.jbit.fsd.dao.impl.UserDaoImpl"> </bean> <bean id="userServiceImpl" class="com.jbit.fsd.service.impl.UserServiceImpl"> <property name="dao" ref="userDao"></property> <!-- 屬性注入 --> </bean> <!-- 配置切面 --> <bean id="serviceLogging" class="com.jbit.fsd.aop.ServiceLoging"></bean> <aop:config> <!-- 配置切入點 --> <aop:pointcut expression="execution(public void addUser(com.jbit.fsd.entity.User))" id="servicePointcut"/> <!-- 將切面和切入點編制在一起--> <aop:aspect ref="serviceLogging"> <aop:before method="beforeService" pointcut-ref="servicePointcut"/> </aop:aspect> </aop:config> </beans>
8.main方法測試:
package com.jbit.fsd.test; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.jbit.fsd.dao.UserDao; import com.jbit.fsd.entity.User; import com.jbit.fsd.printer.Printer; import com.jbit.fsd.service.UserService; import com.jbit.fsd.service.impl.UserServiceImpl; public class Test { /** * @param args */ public static void main(String[] args) { ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml"); UserService dao=(UserService) ac.getBean("userServiceImpl"); dao.addUser(new User()); } }
說明:
1.在.xml文件中需要添加aop命名空間,導入與aop配置相關的標簽。
2.AOP相關的配置在<aop:config>標簽中,切入點的配置在<aop:pointcut>標簽中。
3.execution是切入點的標識符,括號是切入點的表達式,配置需要增強的方法。
4.切入點表達式常用幾種模糊匹配方式:
>public * addUser(com.able.entity.User),“*”表示配置所有類型的返回值。
>public void * (com.able.entity.User), "*"代表匹配所有的方法名。
>public void addUser(..), " .. "表示匹配所有參數個數和類型。
> * com.able.service.*.*( . . ), 表示匹配com.able.service包下面所有類的所有方法。
> * com.able.service . . *(), 表示匹配com.able.service包以及子包下所有類的所有方法。
1.前置增強處理
特點:在目標方法前織入增強處理。
<aop:before method="beforeService" poontcut-ref="servicePointcut"/>
如果想在這個方法中獲得切入點的信息,使用如下方法:
package com.jbit.fsd.aop; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.aspectj.lang.JoinPoint; public class ServiceLoging { private Log log = LogFactory.getLog(this.getClass()); public void beforeService(JoinPoint joinPoint){ System.out.println("aop方法被調用"); System.out.println("連接點對象:"+joinPoint.getTarget().getClass().getSimpleName()); System.out.println("連接點方法:"+joinPoint.getSignature()); System.out.println("連接點方法參數:"+joinPoint.getArgs()[0]); } }
2.後置增強處理
特點:在目標方法正常執行(不出現異常)後織入增強處理。
<aop:after-returning method="afterReturning" pointcut-ref="servicePointcut"/>
如果需要獲取返回值,添加returning="returnVal"
<aop:after-returning method="aft" pointcut-ref="ser" returning="returnVal"/>
public void afterService(Object returnVal){ System.out.println(returnVal); }
3.異常增強處理
特點:在目標方法出現異常後織入增強處理。
<aop:after-throwing mehod=" " pointcut-ref=" " throwing ="ex"/>
如果需要獲取異常對象才添加throwing="ex"
public void afterThrowing(Exception ex){ System.out.println(ex.getMessage()); }
4.最終增強處理
特點:不論方法是否拋異常,都會在目標方法最後織如增強處理,類似與finally。
<aop:after method="after" pointcut-ref="servicePointcut"/>
5.環繞增強處理
特點:在目標方法的前後都可以織入增強處理。
<aop:around method="" pointcut-ref="" />
public Boolean around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("目標方法的參數:"+pjp.getArgs()[0]); Boolean b = null; if (true) { b = (Boolean) pjp.proceed(pjp.getArgs()); } return b; }
Spring的AOP配置常有兩種方式:
>通過schema形式實現簡單AOP配置,也就是上面事例使用方法。
>使用annotation簡化AOP配置。
AspectJ是一個面向切面的框架,AspectJ定義了AOP語法。
使用@AspectJ必須使用jdk5.0以上版本。
步驟:
1.編寫業務類(與上面方法相同)。
2.編寫切面類。
package com.jbit.ssh.aop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect //1.通過注解標記一個切面 public class AspectTest { @Before("execution(* com.jbit.ssh.service..*.*(..))")//2.定義切點和增強類型(切點表達式) public void ba(){ //3.增強處理的fun 4.配置xml System.out.println("前置增強-------"); } @After("execution(* com.jbit.ssh.service..*.*(..))") public void aa(){ System.out.println("後置增強------"); } /** * @before表示前置增強 * @AfterReturning:表示後置增強處理 * @Around:表示環繞增強處理 * @AfterThrowing:表示異常增強處理 * @After:表示最終增強處理 */ }
3.編寫配置文件實現AOP
<?xml version="1.0" encoding="UTF-8"?> <!-- - Application context definition for JPetStore's business layer. - Contains bean references to the transaction manager and to the DAOs in - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation"). --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" > <!--4.基於@AspectJ切面的驅動器 --> <aop:aspectj-autoproxy /> <bean class="com.jbit.ssh.aop.AspectTest"></bean> </beans>