AOP的基础理解

AOP:

事务代理

代理模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aoeGdHrc-1630481036077)(C:\Users\ZYZ\AppData\Roaming\Typora\typora-user-images\image-20210831150255002.png)]

主要包含的三个角色:

  1. 主体类角色:

    可以是接口或者抽象类,需要让目标对象或者代理对象去实现或者继承,目的是为了让目标对象和代理对象具有相同的方法;

  2. 目标类角色:

    他的对象就是目标类对象,核心业务逻辑的具体执行者;

  3. 代理类角色:

    他的对象就是代理对象,内部还有对真是目标对象的引用,负责对目标对象方法的调用,并且在调用前后进行预处理

  • 静态代理
  • 动态代理
    • 创建目标类对象
    • 创建目标类的类加载
    • 获得目标类所实现的接口
    • 创建InvocationHandler接口的实现类对象

AOP在Spring中的作用

提供声明式事务,允许用户自定义切面

特点:

  • 减少代码的重复
  • 提高开发效率
  • 提高可维护性

实现

Spring框架中,会自动根据目标对象是否实现了接口,来选择使用JDK动态代理的方式来实现,还是CGLIB技术来实现

术语

  • 切面/切面类(aspect)
    • 将来要被织入到方法执行 前/后/异常 的时候去执行的代码片段
  • 连接点(joinpoint):
    • Spring的连接点时目标对象里面需要被代理的方法,默认情况时目标对象中所有非final修饰的方法;
    • 如果不是在SpringAOP中,join Point可能还会是属性
  • 切入点(pointCut):
    • 一组连接点的集合,就是一个切入点,因为连接点在Spring中就相当于方法,所以一个切入点也就是一组方法的集合
  • 通知/拦截器(advice):
    • 控制切面/切面类 将来要在目标对象中方法的什么位置执行,例如方法的前面或者方法的后面,或者是在抛出异常的时候
  • 织入(wave)
    • 将切面类织入到指定方法中去执行的动作
  • 目标对象(target):
    • 需要被代理的对象,一般是代理目标对象的一个或者多个指定的方法
  • 代理对象(proxy):
    • 代理目标对象,在完成核心功能的前提下,添加额外的代码去执行

SpringAOP中,通过Advice定义横切逻辑,Spring中支持的5重类型的Advice:

通知类型连接点实现接口
前置通知方法前org.springframework.aop.MethodBeforeAdvice
后置通知方法后org.springframework.aop.AfterReturingAdvice
环绕通知方法前后org.springframework.aop.MethodInterceptor
异常抛出通知方法抛出异常org.springframework.aop.ThrowsAdvice
引介通知类中增加新的方法属性org.springframework.aop.IntroductionInterceptor

即AOP在不改变原有代码的情况下去增加新的功能

案例

首先引入架包
<!--        AOP切面相关的包-->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
1.自定义类来实现AOP

接口类:

public interface ITeacherService {

    void add();

    void delete();

    void update();
}

实现接口

//目标类
@Service
public class ITeacherServiceImpl implements ITeacherService {
    @Override
    public void add() {
        System.out.println("add ....");
    }

    @Override
    public void delete() {
        System.out.println("delete ...");
    }

    @Override
    public void update() {
        System.out.println("update ...");
    }
}

定义切面

@Aspect
@Component
//切面
public class MyAccept {

    //注解配置
    @Pointcut("execution(* com.zyz.aop.service.*.*(..))")
    public void pointcut1(){

    }
	//注解配置
    @Pointcut("execution(* com.zyz.aop.service.*.*(..))")
    public void pointcut2(){

    }

    //通知
    @Before("pointcut1()")
    public void beforeAdvide(){
        System.out.println("before ...");
    }

    @After("pointcut2()")
    public void afterAdvice(){
        System.out.println("after ...");
    }

    public void afterReturn(){

    }
}

配置类

@Configuration
@ComponentScan(basePackages = "com.zyz.aop")
@EnableAspectJAutoProxy
public class AcceptConfig {

}

@EnableAspectJAutoProxy加了该注解才会是切面类的配置生效

测试

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration("classpath:aop.xml")
@ContextConfiguration(classes = AcceptConfig.class)
public class acceptTest {

    @Autowired
    private ITeacherService iTeacherservice;

    @Test
    public void test_1(){
        iTeacherservice.add();
        System.out.println(iTeacherservice.getClass());
    }
}

以上是注解的方式,也可通过配置文件的方法

配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--    目标对象-->
    <bean name="teacherService" class="com.zyz.aop.service.impl.ITeacherServiceImpl"/>

<!--    切面(通知)-->
    <bean name="myAccept" class="com.zyz.aop.accept.MyAccept"/>

<!--    代理-->
    <aop:config>

        <aop:pointcut id="myaop1" expression="execution(* com.zyz.aop.service.*.*(..))"/>
        <aop:pointcut id="myaop2" expression="execution(* com.zyz.aop.service.*.*(..))"/>

        <aop:aspect ref="myAccept">
            <aop:before method="beforeAdvide" pointcut-ref="myaop1"/>
            <aop:after method="afterAdvice" pointcut-ref="myaop2"/>
        </aop:aspect>

    </aop:config>

</beans>
通过Spring API实现

目标接口和目标实现了与上一致

然后去写增强类,这里编写两个,一个前置增强,一个后置增强

public class Log implements MethodBeforeAdvice {
    /**
     *
     * @param method 要执行的目标对象的方法
     * @param objects 被调用方法的参数
     * @param o 目标对象
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName()+"的"+method.getName()+"方法被执行了");
    }
}
public class AfterLog implements AfterReturningAdvice {
    /**
     *
     * @param returnValue 返回值
     * @param method 被调用的方法
     * @param args 被调用的方法的参数列表
     * @param target 被调用的目标对象
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

        System.out.println("执行了"+target.getClass().getName()
        +"的"+method.getName()+"方法,"+"返回值:"+returnValue);
    }
}

aop.xml

    <!--注册bena-->
    <bean id="teacherService" class="com.zyz.aop.service.impl.ITeacherServiceImpl"/>
    <bean id="log" class="com.zyz.aop.accept.Log"/>
    <bean id="afterlog" class="com.zyz.aop.accept.AfterLog"/>
    
    <!--aop的配置-->
    <aop:config>
        <!--切入点 expression:表达式匹配要执行的方法  *:任意返回值类型  service包下以及所有子包的任意类的任意方法-->
        <aop:pointcut id="pointcut" expression="execution(* com.zyz.aop.service..*.*(..))"/>
        <!--环绕执行:advice-ref 执行方法 pointcut-ref:切入点-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
    </aop:config>


</beans>

测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:aop.xml")
//@ContextConfiguration(classes = AcceptConfig.class)
public class acceptTest {

    @Autowired
    private ITeacherService iTeacherservice;

    @Test
    public void test_2(){
        iTeacherservice.add();
        System.out.println(iTeacherservice.getClass());
    }
}

Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理

Spring-day3-作业

1.请按照自己的理解描述AOP是什么

AOP:意思为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护技术。利用AOP可以对业务逻辑层的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。

2.请使用xml配置,完成环绕、前置、返回后、异常等通知

(1)切面类:

public class RoleAspect {
  public RoleVerifier roleVerifier;
  public void before(Role role) {
    System.out.println("before..." + role.getRoleName() + "引入了参数");
 }
  public void after() {
    System.out.println("after...");
 }
  public void afterReturning() {
    System.out.println("afterReturning");
 }
  public void afterThrowing() {
    System.out.println("afterThrowing");
 }
  //环绕通知
  public void around(ProceedingJoinPoint jp) {
    System.out.println("around-before");
    try {
      jp.proceed();
   } catch (Throwable throwable) {
      throwable.printStackTrace();
   }
    System.out.println("around-after");
 }
}

(2)IRoleService以及RoleServiceImpl:

public interface IRoleService {
	public void print(Role role)throws Exception;
}
@Service("roleService")
public class RoleServiceImpl implements IRoleService{
@Override
public void print(Role role) throws Exception {
 	System.out.println("print方法执行");
}
}

role.java

@Data
@Component
public class Role implements Serializable {
    @Value("1")
    private Integer id;

    @Value("admin")
    private String username;

    @Value("123456")
    private String password;
}

Unbound pointcut parameter

由于前置方法中传入了参数,所以再配置前置执行方法时要传入参数,则不能用pointcut-ref而要使用pointcut

xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean name="RoleAspect" class="com.zyz.work.aspect.RoleAspect"/>

    <bean name="role" class="com.zyz.bean.Role"/>

    
    <aop:config>
        
        <aop:pointcut id="p1"  expression="execution(* com.zyz.work.service.*.*(..))"/>

        <aop:aspect ref="RoleAspect">
            <aop:before method="before"  pointcut="execution(* com.zyz.work.service.*.*(..)) and args(role)"/>
            <aop:after method="after" pointcut-ref="p1"/>
            <aop:after-returning method="afterReturning" pointcut-ref="p1"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="p1"/>
            <aop:around method="around" pointcut-ref="p1"/>

        </aop:aspect>
    </aop:config>

    <context:component-scan base-package="com.zyz.work.service"/>

</beans>

test

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(classes = RoleConfig.class)
@ContextConfiguration(locations = "classpath:roleAop.xml")
public class RoleTest {

    @Autowired
    private Role role;

    @Autowired
    private RoleService roleService;

    @Test
    public void  test() throws Exception {

//        System.out.println(role);
        roleService.print(role);
    }
}
3.谈谈 Spring 事务管理的三个重要概念。
  • 事务的隔离级别
  • 事务的传播行为
  • 事务的回滚原则
  • 事务的只读属性
  • 事务超时
4.事务的隔离级别是
  1. ISOLATION_DEFAULT:事务默认的隔离级别
    1. MYSQL:可重复读
    2. ORACLE:读已提交
  2. ISOLATION_UNCOMMITTED:读未提交
  3. ISOLATION_COMMITTED:读已提交
  4. ISOLATION_REPEATABLE_READ:可重复读
  5. ISOLATION_SERIALIZABLE:串行化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值