引言:AOP全稱為Aspect Oriented Programming即為面向面變成向胡,它是一種變成思想;Spring為了管理日志信息惊完,事務(wù)信息以及異常等信息將這種思想加入到了自己的架構(gòu)中僵芹;我們稱之為SpringAOP;
一:究竟什么是面向切面編程专执?
百度百科:通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)淮捆。AOP是OOP的延續(xù);是軟件開發(fā)中的一個熱點本股,也是Spring框架中的一個重要內(nèi)容攀痊,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務(wù)邏輯的各個部分進(jìn)行隔離拄显,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低苟径,提高程序的可重用性,同時提高了開發(fā)的效率躬审。
引用知乎上一人回答:就是在程序執(zhí)行過程中動態(tài)地將代碼切入到類的指定方法或者指定位置上的編程思想棘街;
二:怎么使用?
在java的Spring框架中具體有兩種實現(xiàn)方法承边,一種是通過JDK的動態(tài)代理實現(xiàn)遭殉,一種是通過Cglib的動態(tài)代理實現(xiàn);
1:早期的Aop:
A:通過JDK的動態(tài)代理實現(xiàn):
a:需要接口b:實現(xiàn)類(代理類)c:織入類d:代理類
//接口類
package com.cp.insist.dao;
import com.cp.insist.entity.User;
public interface InteUserDao {
public void updateUser(Integer id ,User user);
}
//實現(xiàn)類
public class userDao implements InteUserDao{
@Override
public void updateUser(Integer id,User user) {
System.out.println("更新用戶的id為:"+id+"用戶為"+user);
}
}
package com.cp.insist.dao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* java動態(tài)代理類必須要有一個接口
這是一個織入類
* @author 陳鵬
*
*/
public class UserHander implements InvocationHandler{
private Object target;
/**
*
* @Description:通過構(gòu)造方法去傳遞目標(biāo)對象
* @創(chuàng)建時間 2016年7月18日
* @創(chuàng)建人 陳鵬
* @throws
*/
public UserHander(Object source){
this.target=source;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("開始提交事務(wù)了博助。险污。。");
// 執(zhí)行代理的方法
Object object = method.invoke(target, args);
System.out.println("提交事務(wù)成功了8辉馈;着础!");
return object;
}
}
/測試類
package com.cp.insist.test;
import java.lang.reflect.Proxy;
import com.cp.insist.dao.InteUserDao;
import com.cp.insist.dao.UserHander;
import com.cp.insist.dao.userDao;
public class MainTest {
public static void main(String[] args) {
1:闖將一個實現(xiàn)類窖式,被代理的對象
IUserDao userDao = new UserDaoImpl();
2:動態(tài)處理對象
UserHandler userHandler = new UserHandler(userDao);
3:創(chuàng)建一個代理對象
IUserDao proxy = (IUserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
userHandler);
proxy.saveUser(new User());
}
}
使用cglib來進(jìn)行Aop的動態(tài)代理的處理蚁飒,簡化了jdk的Aop動態(tài)代理的處理
不需要使用接口;
代理類的對象本身并不真正實現(xiàn)服務(wù)萝喘,而是通過調(diào)用委托類的對象的相關(guān)方法淮逻,來提供特定的服務(wù)。
1:建一個dao類阁簸,再建一個動態(tài)的處理類實現(xiàn)MethodInterceptor類弦蹂;
2:并且重寫里面的方法,再調(diào)用ivoinvokeSuper方法
//被代理類
public class userDao {
public void saveUser(User user){
System.out.println("進(jìn)入了user的保存方法");
}
}
//織入類
public class userProxy implements MethodInterceptor{
//增強(qiáng)對象
private Enhancer enhancer = new Enhancer();
public Object getProxyObject(Class clz){
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] arrO,
MethodProxy proxy) throws Throwable {
System.out.println("這里提交事務(wù)G拷选凸椿!");
//調(diào)用方法
Object obj = proxy.invokeSuper(arg0, arrO);
System.out.println("主要業(yè)務(wù)");
return obj;
}
}
測試類:
public class Test {
public static void main(String[] args) {
userProxy proxy = new userProxy();
userDao user = (userDao)proxy.getProxyObject(userDao.class);
user.saveUser(new User());
}
}
2:引入注解之后的Aop
同樣也分jdk的動態(tài)代理和cglib的動態(tài)代理
這里我們只將jdk的動態(tài)代理
//接口
public interface Iuser {
public void say(String name) throws SQLException;
}
//實現(xiàn)類
public class UserImp implements Iuser{
@Override
public void say(String name) throws SQLException {
System.out.println("我是一個"+name+"通知"+"目的方法");
throw new SQLException("對不起查詢失敗");
}
}
//通知類:這是一個后置通知
public class adviceAfter implements AfterReturningAdvice{
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
System.out.println("我是一個后置通知");
}
}
//配置文件:因為我們采用的注解方式:利用IOC思想;讓容器去替我們管理對象翅溺,所以在相應(yīng)的配置文件我們需要:
<property name="optimize" value="false"></property>通過設(shè)置它的值我們可以選擇使用jdk的動態(tài)代理還是cglib的動態(tài)代理脑漫;默認(rèn)為false髓抑,采用jdk的動態(tài)代理
<!--通知類-->
<bean id="advice2" class="com.chenpeng.dao2.MethodInterceptorAdvice"></bean>
<!--實現(xiàn)類-->
<bean id ="userimp" class="com.chenpeng.dao2.UserImp"></bean>
<!--根據(jù)通知類和實現(xiàn)類去獲取代理對像-->
<bean id="factory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userimp"></property>
<property name="interfaces" value="com.chenpeng.dao2.Iuser"></property>
<!-- 第一種方法:多個通知時 -->
<!-- <property name="interceptorNames" value="advice,advice1,advice2,exception"></property> -->
<!-- 第二種方法:多個通知時 -->
<!-- <property name="interceptorNames">
<list>
<value>advice</value>
<value>advice1</value>
<value>advice2</value>
<value>exception</value>
</list>
</property> -->
<!-- 第三種方法:多個通知時 -->
<property name="interceptorNames">
<list>
<idref bean="advice"/>
<idref bean="advice1"></idref>
<idref bean="advice2"></idref>
<idref bean="exception"></idref>
</list>
</property>
</bean>
//測試類
public class test2 {
public static void main(String[] args) {
ApplicationContext content = new ClassPathXmlApplicationContext("classpath:com/chenpeng/dao2/bean.xml");
//jdk動態(tài)代理使用接口轉(zhuǎn)型;cjlib的動態(tài)代理使用具體類轉(zhuǎn)型
Iuser user = (com.chenpeng.dao2.Iuser)content.getBean("factory");
user.say("前置");
}
}
3:最新的AOP使用Aspectj將切面和植入類進(jìn)行完美結(jié)合省去很多代碼
接口類
public interface Iuser {
public void addUser();
public void addUser1();
public void updateUser();
public void updateUser(int a);
}
實現(xiàn)類:
@Component
public class cpUserImp implements Iuser{
@Override
public void addUser() {
System.out.println("我是一個addUser的方法");
}
@Override
public void updateUser() {
System.out.println("我是一個updateUser的方法");
}
@Override
public void addUser1() {
// TODO Auto-generated method stub
System.out.println("我是一個addUser1的方法");
}
@Override
public void updateUser(int a) {
// TODO Auto-generated method stub
System.out.println("我是一個帶參數(shù)的update方法");
}
}
織入類+切面
@Component
@Aspect
public class aspectAdvitor {
@Before("execution(* add*(..))")//攔截指定的方法
public void say(){
System.out.println("我是一個aspectj版本的aop的方法");
}
@AfterReturning("execution(* update*(..))&&args(int,..)")
public void work(){
System.out.println("我是一個update的work后置通知方法");
}
//環(huán)繞型通知
@Around("execution(* update*(..))")
public void round(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("事務(wù)開始");
joinPoint.proceed();
System.out.println("事務(wù)提交");
}
}
關(guān)于配置文件:由于我們采用了注解
第一種方式:
<!-- 表示開啟了Aspect模式的Aop -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"></bean>
<!--切面+織入類-->
<bean class="com.chenpeng.dao4.AspectAop"></bean>
<!--具體類-->
<bean id="user" class="com.chenpeng.dao4.UserImp"></bean>
第二種方式:
<!--掃包:將所有添加注解的類相關(guān)對象都進(jìn)行實例化-->
<context:component-scan base-package="com.chenpeng.dao4.**"></context:component-scan>
<!-- 表示開啟了Aspect模式的Aop -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
第四種方式:主體的類文件和第三種一樣优幸,我們可以將具體的切入點在配置文件書寫吨拍;更加方便:
<context:component-scan base-package="com.chenpeng.dao6"></context:component-scan>
<aop:config>
<!-- 可以將切點單獨定義出來 -->
<aop:pointcut expression="execution(* update*(..))" id="roundAdvisor"/>
<!---ref="aspectAdvitor"-這個就是我們定義的切面和通知類由于掃包了,默認(rèn)的bean的id就是類名首字母小寫->
<aop:aspect ref="aspectAdvitor">
<!--切面類以及執(zhí)行的方法-->
<aop:after method="say" pointcut="execution(* add*(..))"/>
<!-- 引用上面定義的切點 -->
<aop:around method="round" pointcut-ref="roundAdvisor"/>
</aop:aspect>
</aop:config>
以上就是自己學(xué)習(xí)spring中的AOP的相關(guān)筆記网杆;如果有不對的地方還望大家及時指點羹饰;