关于Spring框架AOP的个人理解
1.AOP的概念:
百度结果:
AOP为Aspect Oriented
Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
个人理解:
AOP是在不通过修改原有业务的基础上,为了增强某些业务的功能而诞生的一种编程思想,至于这个切面我希望可以通过下面的图示来说明。
AOP切面开发的理解:
正常代码是纵向开发的,然而为了解决在更改代码时防止对代码实现误改和其他原因导致源码出问题,则要在每个类都添加一个代理类,
而这个代理类是出现在开发过程的横向上的(就像是在整个开发过程中拓展出的阶段),因此称之为横向(切面开发),使用代理机制来增加一些功能上的开发。
2.AOP的底层原理:
AOP思想的底层原理使用的是动态代理
代理模式java基础阶段所接触的一种思想,是在原有类的基础上增加代理类来实现原有类的方法并进行一些业务增强。
静态代理示例:
①定义一个出租接口
public interface Rent {
void rent();
}
②创建真实的角色
public class Host {
public void rent(){
System.out.println("户主来出租房子");
}
}
③创建代理角色
public class HostProxy implements Rent {
private Host host;
public HostProxy() {
}
public HostProxy(Host host) {
this.host = host;
}
@Override
public void rent() {
host.rent();
}
//增强的业务
public void seehouse(){
System.out.println("我是中介,带你看房");
}
}
④客户端访问代理角色
public class Client {
public static void main(String[] args) {
Host host =new Host();
HostProxy hostproxy = new HostProxy(host);
hostproxy.rent();
}
}
至此户主只需要专心租房,不需要找租客,而中介则是被代理出租的对象,可以附加一些功能
静态代理的好处:
a.可以使真正的角色的操作更加纯粹,不用去关注一些公共的事务
b.公共也就可以交给代理角色,实现业务的分工
c.公共业务发生拓展的时候,方便集中管理
缺点:
一个真实的角色机会产生一个代理角色,代码量会翻倍开发效率降低
动态代理:
动态代理则是用到了java基础的反射
主要用到了Proxy类的newnewProxyInstance方法进行代理对象的创建
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDao userDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(new UserDaoImpl()));
int add = userDao.add(1, 2);
System.out.println(add);
}
class UserDaoProxy implements InvocationHandler {
private Object obj;
public UserDaoProxy(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("在方法之前执行"+method.getName()+"传递的参数"+ Arrays.toString(args));
Object res = method.invoke(obj, args);
System.out.println("执行完方法后"+obj);
return res;
}
}
2.AOP的实现
2.1AOP的操作术语
①连接点:类里的那些方法可以被增强,这些方法称为连接点
②切入点:实际被真正增强的方法称为切入点
③通知(增强)实际增强的逻辑部分称为通知
通知有多种类型
a.前置,后置,环绕,异常,最终通知
④切面(是一个动作)
把通知应用到切入点的过程
2.2AOP操作的准备
1…Spring框架一般都是基于AspectJ实现AOP操作
①什么是AspectJ不是spring组成部分,独立AOP框架,一般把AspectJ和spring一起使用进行aop操作
②基于Xml配置文件的操作实现(不常使用)
基于注解的方式实现(使用)
2.引入依赖jar包
3.切入点的表达式
①切入点表达式的作用:知道对哪个类里面的哪个方法进行增强
②语法结构:execution([权限修饰符][返回类型][类的全路径][方法名称]([参数列表]))
举例a:
对com.guo.Bookdao类里的add方法增强:
execution((这个星号表示任意的修饰符)com.guo.Bookdao.add(…))
举例b.
对com.guo.book类中的所有方法进行增强
execution(com.guo.Book.(…))
举例c:
对com.guo中的所有类和所有方法都进行增强
execution(com.guo..(…))
2.3AOP操作(AspectJ注解)
①创建类,在类里面定义方法
②创建增强类,编写增强逻辑
③进行通知的配置
a.在spring配置文件中开启注解扫描
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"
<context:component-scan base-package="Aop"></context:component-scan>
b.使用注解创建User和UserProxy对象
@Component
public class User {
@Component
public class UserProxy {
c.在增强类上添加注解@Aspect
@Component
@Aspect
public class UserProxy {
}
d.在spring配置文件中开启生成代理对象
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
④配置不同类型的通知
在增强通知的方法上添加@通知类型的注解
如要在之前增强aop包下的User类的add方法:(以此类推)
a.前置通知
@Before(value = "execution(* Aop.User.add(..))")
public void before(){
System.out.println("before....");
}
b.后置通知
@after(value=)
@afterreturning(value=)---------【返回通知,有返回时才会执行当有异常时不会执行】
c.环绕通知
@around(value=)在执行方法之前和之后都可以执行,通过参数来控制被增强方法的执行
@Around(value = "execution(* Aop.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println();
proceedingJoinPoint.proceed();
System.out.println();
}
d.异常通知
@afterthrowing(value=)
2.4相同切入点的抽取:
对于上面因为切入点都是相同的,所有可以提取出来为一个方法,在后面调用时只需要提供方法即可
@Pointcut(value = "execution(* Aop.User.add(..))")
public void pointcut(){
}
@Before(value = "pointcut()")
public void before(){
System.out.println("before....");
}
当有多个增强类对同一个方法进行增强,设置增强类优先级
在增强类上面添加注解@Order(数字值类型),数字值越小,优先级越高
@Component
@Aspect
@Order(1)
public class UserProxy {
}
3.AOP操作
1.创建两个类,一个增强类另一个被增强类,创建方法
2.在spring配置文件中创建两个类的对象
<bean id="user" class="Aop.User"></bean>
<bean id="userProxy" class="Aop.UserProxy"></bean>
3.在配置文件中配置切入点
<aop:config>
<aop:pointcut id="p" expression="execution(* Aop.User.add(..))"/>
<aop:aspect ref="userProxy">
<aop:before method="before" pointcut-ref="p"></aop:before>
</aop:aspect>
</aop:config>
完全注解的模式:
@ComponentScan(basePackages = {"Aop"})------------------》来代替:
<context:component-scan base-package="Aop"></context:component-scan>
@EnableAspectJAutoProxy(proxyTargetClass = true)----------》来代替
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Configuration
public class ConfigAop {
}
当完全使用注解时,在获取bean时就要使用
ApplicationContext context =new AnnotationConfigApplicationContext();