SpringAOP

Spring存在意义:

    Java是一个面向对象(OOP)的语言,但它有一些弊端,比如当我们需要为多个不具有继承关系的对象引入一个公共行为,例如日志,权限验证,事务等功能时,只能在在每个对象里引用公共行为,这样做不便于维护,而且有大量重复代码。AOP的出现弥补了OOP的这点不足。

1.代理模式:

      代理模式:为其他对象提供一种代理以控制对这个对象的访问。即A要做一件事,在没有代理的时候需要自己动手,当有了代理B以后就可以让B去替他完成;

2.静态代理:

   

public interface IUserDAO {
    public void run();
}
public class UserDAO implements IUserDAO {
    @Override
    public void run() {
        System.out.println("事务运行");
    }
}
public class Proxy implements IUserDAO {
    private IUserDAO target=new UserDAO();
    @Override
    public void run() {
        System.out.println("事务运行前");
        target.run();
        System.out.println("事务运行后");
    }
}
public class Test {
    public static void main(String[] args) {
        IUserDAO proxy=new Proxy();
        proxy.run();
    }
}

静态代理虽然保证了业务类只需关注逻辑本身,代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理。再者,如果增加一个方法,除了实现类需要实现这个方法外,所有的代理类也要实现此方法。增加了代码的维护成本,为了减少成本就需要使用动态代理。

3.动态代理:

动态代理模式:动态代理类的源码是在程序运行期间通过JVM反射等机制动态生成,代理类和委托类的关系是运行时才确定的。

public interface IUserDAO {
    public void save();
    public void find();
}
class RealUser implements IUserDAO{

    @Override
    public void save() {
        System.out.println("模拟:保存用户");
    }

    @Override
    public void find() {
        System.out.println("查询");
    }
}
class ProxyFactory{
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }
    public Object getProxyInstance(){
        Object proxy=Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//目标对象使用的类加载
                target.getClass().getInterfaces(),//目标对象实现的接口
                //执行代理对象方法是触发,
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //执行方法名
                        String name=method.getName();
                        //返回值
                        Object result=null;
                        if("find".equals(name)){
                            result=method.invoke(target,args);
                        }else {
                            System.out.println("开始事务");
                            result=method.invoke(target,args);
                            System.out.println("事务提交");
                        }return result;

                    }
                }
        );return proxy;
    }
}
class Client{
    public static void main(String[] args) {
        IUserDAO target=new RealUser();
        System.out.println("目标对象:"+target.getClass());
        IUserDAO proxy=(IUserDAO) new ProxyFactory(target).getProxyInstance();
        System.out.println("代理对象:"+proxy.getClass());
        proxy.save();
    }
}

 

JDK代理:目标类要有实现的接口;

CGLIB代理:目标类没有实现接口,其是以动态生成目标类的子类来实现的,目标类不能被final修饰(不能继承);


4.SpringAOP原理:

SpringAOP基本理论:

  • 面向切面编程:

       DI有助于对象之间的解耦;

       AOP实现横切关注点与其所影响的对象之间的解耦;(散布与应用中多处的功能为横切关注点)

  • 通知(Advice):

      定义了切面是什么以及何处使用,即做什么和什么时候做;

  • 连接点(JoinPoint):

      spring允许使用通知的地方,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点;

  • 切入点(PointCut):

     在连接点的基础上,来定义切入点,一个类里,有许多方法,就有许多个连接点,但是你并不想在所有方法附近都使用通知(使用叫织入),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法;

"execution(* com.answer.springAOP2.IUserDAO.save())"
  • 切面(Aspect):

     即通知和切入点的结合,通知是做什么和什么时候做,切入点是在哪做;

  • 引入(Introduction):

      允许我们向现有的类添加新方法属性,就是把切面(也就是新方法属性:通知定义的)用到目标类中;

  • 织入(Weaving):

       把切面应用到目标对象来创建新的代理对象的过程。有3种方式,spring采用的是运行时。

  关键就是:切点定义了哪些连接点会得到通知;

  1. 编译期:切面在目标类编译时被织入,需要特殊的编译器;
  2. 类加载期:切面在目标类加载到JVM时织入,需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前加强该目标类的字节码;
  3. 运行期:切面在运行的某个时刻被织入,AOP为目标类动态创建代理对象;

A.SpringAOP是动态代理模式;

B.创建容器对象的时候,根据切入点表达式拦截的类,生成代理对象;

C.如果目标对象有实现接口,使用jdk代理。如果目标对象没有实现接口,则使用Cglib代理。然后从容器获取代理后的对象,在运行期植入"切面"类的方法;


SpringAOP(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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="cglib" class="com.answer.springAOP1.Cglib"></bean>
    <bean id="jdk" class="com.answer.springAOP1.Jdk"></bean>
    <bean id="transcantionaop" class="com.answer.springAOP1.TranscationAOP"></bean>
    <aop:config>
        <!-- 切入点表达式定义-->
        <aop:pointcut id="transcationPointcut" expression="execution(* com.answer.springAOP1.*.*(..))"></aop:pointcut>
        <aop:aspect ref="transcantionaop">
            <aop:before method="beforeTransaction" pointcut-ref="transcationPointcut"></aop:before>
            <aop:after method="afterTranscation" pointcut-ref="transcationPointcut"></aop:after>
            <aop:after-returning method="afterReturn" pointcut-ref="transcationPointcut" returning="result"></aop:after-returning>
            <aop:around method="round" pointcut-ref="transcationPointcut"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>
public interface IUserDAO {
    public String save();
}
class Cglib{
    public String save(){
        System.out.println("Cglib代理");
        return "不需要接口实现";
    }
}
class Jdk implements IUserDAO{

    @Override
    public String save() {
        System.out.println("JDK代理");
        return "需要一个接口实现";
    }
}
class TranscationAOP{
    public void beforeTransaction(){
        System.out.println("前置增强");
    }
    public void afterTranscation(){
        System.out.println("后置增强");
    }
    public void afterReturn(Object result){

        System.out.println("后置返回增强"+result);
    }
    public void afterThrow(){
        System.out.println("后置异常增强");
    }
    public Object round(ProceedingJoinPoint pjp) throws Throwable {
        Object result=null;
        System.out.println("环绕前:");
        result=pjp.proceed();
        System.out.println("环绕后:");
        return result;
    }
}
class Test{
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("aop1.xml");
        IUserDAO userDAO=(IUserDAO) applicationContext.getBean("jdk");
        //System.out.println(userDAO.getClass());
        userDAO.save();
        Cglib cglib=(Cglib) applicationContext.getBean("cglib");
        cglib.save();
    }
}


SpringAOP(注解):

<?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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.answer.springAOP2">
        <context:include-filter type="annotation"	expression="org.aspectj.lang.annotation.Aspect"/>
    </context:component-scan>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
public interface IUserDAO {
    public String save();
    public void mine();
}

@Component("jdk")
public class Jdk implements IUserDAO {
    @Override
    public String save() {
        System.out.println("JDK动态代理");
        return "需要接口";
    }

    @Override
    public void mine() {
        System.out.println("我不需要切面");
    }
}

@Component("cglib")
public class Cglib {
    public String save(){
        System.out.println("CGLIB动态代理");
        return "不需要接口";
    }
}
@Aspect
public class MyAspect {
    @Before("execution(* com.answer.springAOP2.IUserDAO.save())")
    public void beforeTransaction(){
        System.out.println("前置增强");
    }
    @After("execution(* com.answer.springAOP2.IUserDAO.save())")
    public void afterTranscation(){
        System.out.println("后置增强");
    }
    @AfterReturning(value = "execution(* com.answer.springAOP2.IUserDAO.save())",returning = "result")
    public void afterReturn(Object result){

        System.out.println("后置返回增强"+result);
    }
    @AfterThrowing("execution(* com.answer.springAOP2.IUserDAO.save())")
    public void afterThrow(){
        System.out.println("后置异常增强");
    }
    @Around("execution(* com.answer.springAOP2.IUserDAO.save())")
    public Object round(ProceedingJoinPoint pjp) throws Throwable {
        Object result=null;
        System.out.println("环绕前:");
        result=pjp.proceed();
        System.out.println("环绕后:");
        return result;
    }
}

 

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("aop2.xml");
        IUserDAO iUserDAO=(IUserDAO) applicationContext.getBean("jdk");
        iUserDAO.save();
        iUserDAO.mine();
        //Cglib cglib=(Cglib) applicationContext.getBean("cglib");
        //cglib.save();
    }
}

 


SpringAOP用处:

    1.Spring声明式事务管理配置。

    2.Controller层的参数校验。

    3.使用Spring AOP实现MySQL数据库读写分离案例分析

    4.在执行方法前,判断是否具有权限。

    5.对部分函数的调用进行日志记录。监控部分重要函数,若抛出指定的异常,可以以短信或邮件方式通知相关人员。

    6.信息过滤,页面转发等;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dream答案

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值