*为什么使用AOP
1.写死代码
接口
public interface UserService{
public void add();
public void delete();
public void updata();
}
实现类
public class UserServiceImp implements UserService {
@Override
public void add(){
System.out.println("Before");
System.out.println("add ");
System.out.println("After");
}
public void delete(){
System.out.println("Before");
System.out.println("delete ");
System.out.println("After");
}
public void updata(){
System.out.println("Before");
System.out.println("updata ");
System.out.println("After");
}
private void before() {
System.out.println("Before");
}
private void after() {
System.out.println("After");
}
}
before() 与 after() 方法写死在 sayHello() 方法体中了.那么你每实现一个类都要给类中加入这两个方法,很不符合代码的可重用性。所以我们要引入AOP这个概念。我们要将befor(),after()这种方法定义在一个切面类里面,当要使用时把它们织入(weaving)到目标类中*。通俗来讲就相当于一把刀去切一坨面,而对于面而来,我们就一定是横着来切它,这种简称为“横切”,下面我们就要来讲如何来实现这把刀。*
1.AOP概述
1)在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
2)AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
3)利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
4)AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
5)经典应用:事务管理、性能监视、安全检查、缓存 、日志等
6)Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
7)AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
2.AOP的术语
1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3.PointCut 切入点:已经被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7. Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。
一个切入点和一个通知,组成成一个特殊的面。
3.AOP实现原理
-
**AOP底层使用代理机制进行实现**
4.静态代理
最简单的解决方案就是使用静态代理模式了,我们单独为 UserServiceImpl 这个类写一个代理类:
UserServiceProxy.java
package com.liheng.proxy;
import com.liheng.service.UserService;
import com.liheng.service.UserServiceImp;
public class UserServiceProxy implements UserService {
private UserServiceImp userService;
public UserServiceProxy(UserServiceImp userService) {
this.userService = userService;
}
@Override
public void add(){
System.out.println("Before");
System.out.println("add ");
System.out.println("After");
}
public void delete(){
System.out.println("Before");
System.out.println("delete ");
System.out.println("After");
}
public void updata(){
System.out.println("Before");
System.out.println("updata ");
System.out.println("After");
}
private void before() {
System.out.println("Before");
}
private void after() {
System.out.println("After");
}
}
UserTest.java:
package com.liheng.test;
import org.junit.Test;
import com.liheng.proxy.UserServiceProxy;
import com.liheng.service.UserService;
import com.liheng.service.UserServiceImp;
public class UserTest {
@Test
public void test(){
UserService userServiceProxy = new UserServiceProxy(new UserServiceImp());
userServiceProxy.add();
userServiceProxy.delete();
userServiceProxy.updata();
}
}
这样写没错,但是有个问题,XxxProxy 这样的类会越来越多,如何才能将这些代理类尽可能减少呢?最好只有一个代理类。
5.JDK动态代理
接口:
public interface UserService {
public void add();
public void delete();
public void updata();
}
实现类:
public class UserServiceImp implements UserService {
@Override
public void add() {
System.out.println("add User");
}
@Override
public void delete() {
System.out.println("delete User");
}
@Override
public void updata() {
System.out.println("updata User");
}
}
我们将before(),after()这两个方法放到一个切面类中:
package com.liheng.proxy;
public class MyAspect {
public void before() {
System.out.println("Before");
}
public void after() {
System.out.println("After");
}
}
代理工厂类,用来生产代理对象:
package com.liheng.factoty;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.liheng.proxy.MyAspect;
import com.liheng.service.UserService;
import com.liheng.service.UserServiceImp;
public class ProxyFactory {
public UserService createUserService(){
// 1.目标类
final UserService userService = new UserServiceImp();
// 2.切面类
final MyAspect myAspect = new MyAspect();
// 3.代理类 将切面类通知到目标类中
/* newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 参数1.类加载器,一般写当前类
* 参数2.被代理类对象要实现的接口
* 参数3.处理类,一般写匿名类
* */
UserService proxy =(UserService) Proxy.newProxyInstance(
ProxyFactory.class.getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
myAspect.before();
// 放行
Object obj = method.invoke(userService, args);
myAspect.after();
return obj;
}
});
return proxy;
}
}
测试类:
package com.liheng.test;
import org.junit.Test;
import com.liheng.factoty.ProxyFactory;
import com.liheng.service.UserService;
public class UserTest2 {
@Test
public void test(){
UserService userService = new ProxyFactory().createUserService();
userService.add();
}
}
6.cglib动态代理实现
我们使用开源的 CGLib 类库可以代理没有接口的类,这样就弥补了 JDK 的不足
cjlib和JDK代理的区别
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法不要声明成final ,final可以阻止继承和多态。
7.AOP联盟实现半自动代理
需要多导入两个jar包
切面类:
beans.xml
8.AOP全自动编程
9.AspectJ实现AOP
接口
package com.liheng.service;
public interface IUserService {
public void addUser();
public void deleteUser();
public void updataUser();
public int deleteUser(int id);
}
实现类
package com.liheng.service;
public class UserServiceImp implements IUserService{
@Override
public void addUser() {
System.out.println("add User");
}
@Override
public void deleteUser() {
System.out.println("delete User");
}
@Override
public void updataUser() {
System.out.println("updata User");
}
@Override
public int deleteUser(int id) {
return id;
}
}
切面类
package com.liheng.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before(){
System.out.println("前置通知");
}
public void afterReturning(){
System.out.println("后置通知");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知");
// System.out.println("开启事务");
// 放行
Object obj = pjp.proceed();
// System.out.println("提交事务");
return obj;
}
}
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id ="userService" class="com.liheng.service.UserServiceImp"></bean>
<bean id = "myAspect" class= "com.liheng.aspect.MyAspect"></bean>
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(* com.liheng.service.UserServiceImp.*(..))"/>
<aop:before method="before" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
</beans>
测试类
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.liheng.service.IUserService;
public class TestDemo {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans4.xml");
IUserService userService = (IUserService) context.getBean("userService");
userService.addUser();
}
}
给一张思维导图,总结一下知识点
Sp