Spring AOP初试

AOP基本概念

切面(Aspect):组织多个通知(增强处理,切面方法,advice)
连接点(Joinpoint):程序执行中明确的点,大概理解成程序执行中的点吧,比如方法执行,异常抛出。Spring AOP中就是方法调用。
通知(增强处理、切面方法、advice):有around、before、after、after returning、after throwing。
切入点(Point Cut):可以插入advice的JoinPoint。当某个连接点满足要求时,该连接点被添加上增强处理。
引入:将方法或字段添加到类中。Spring允许将新的接口引入到任何被处理的类中。
目标对象:被AOP框架进行增强处理的对象。Spring中的AOP代理可以是JDK动态代理(实现接口的目标对象),也可以是cglib代理(不实现接口的目标对象)。
织入(weaving):将增强处理添加到目标对象中,并创建一个被增强对象(AOP 代理)的过程就是织入。织入有两种方式:编译时增强(AspectJ)和运行时增强(如spring AOP)。

使用注解加配置实现

利用IDEA新建web+maven工程

配置信息

web.xml:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

applicationContext.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" xmlns:mvc="http://www.springframework.org/schema/mvc" 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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <context:annotation-config />

    <context:component-scan base-package="com.mitsuhide.*" />
    <!--</context:component-scan>-->

    <aop:aspectj-autoproxy/>

    <mvc:annotation-driven />

</beans>

注意:applicationContext.xml 如果是用maven配置的,一定要放在resource中,否则classpath*或者classpath找不到的。

pom.xml(IDEA的maven实在是好用,最喜欢这点)
加入了(好像aop的只有aop和aspectJ、cglib):

spring-context
spring-webmvc
spring-web
spring-aop
aspectjrt
aspectjweaver
spring-tx
spring-aspects
cglib-nodep

关键代码

Controller

@Controller
@RequestMapping("/mvc")
public class HelloController {
    @RequestMapping("/hello")
    public @ResponseBody String hello () {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// Athlete zly = (Athlete)context.getBean("Athlete");
        Player zly = (Player)context.getBean("Athlete");
        return zly.sayHello();
    }
}

这里有个很有意思的事情,因为Athlete 被绑在切面方法中了,所以获取bean这里需要分情况:
1、Athlete实现了接口
这种情况走的是JDK动态代理,获取bean其实是获取的接口,向上转型了:

Player zly = (Player)context.getBean("Athlete");

2、Athlete一个接口都没实现
这种情况走的是cglib的方式,直接获取类:

Athlete zly = (Athlete)context.getBean("Athlete");

Aspect

@Aspect
@Component
public class PlayerAspect extends CustomizableTraceInterceptor {
    @Pointcut("execution( * com.mitsuhide.entity.common.Athlete.*(..))")
    private void aspectMethod(){}//定义一个切入点

    @Before("aspectMethod()")
    public void before () {
        System.out.println("方法执行前执行...... By mitsuhide aspect.");
    }

    @After("aspectMethod()")
    public void after () {
        System.out.println("方法执行后执行...... By mitsuhide aspect.");
    }
}

这里也可以这样写(可以实现接口也可以不实现,因为网上搜的好多教程都是实现了的):

@Before("execution( * com.mitsuhide.entity.common.Athlete.*(..))")

Bean:

@Component("Athlete")
public class Athlete implements Player {
    @Autowired
    private Basketball ball;

    public Basketball getBall() {
        return ball;
    }

    public void setBall(Basketball ball) {
        this.ball = ball;
    }

    public String sayHello () {
        String helloWords = "Hi, I am a " + ball.getBallName() + " player";
        return helloWords;
    }

    @PostConstruct
    public void init () {
        System.out.println("Athlete bean is initializing! By mitsuhide.");
    }

    @PreDestroy
    public void destroy () {
        System.out.println("Athlete bean is destroying! By mitsuhide.");
    }
}

遇到的问题

1、applicationContext.xml找不到

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

报找不到文件错误,这个是因为maven路径的问题。把xml文件放到resource目录下可解决。

2、切面方法不执行
切面类要同时加上@Aspect,@Component才会执行切面方法。网上教程大多只有·Aspect,我也不造为啥。

3、上面说的需要区分是接口的代理还是类的代理
网上也有另外一种解决办法:

在aop:config标签中添加 proxy-target-class=”true” 即可。
由于生成代理类有两种方式:JDK和CGLIB,一种是基于接口的,一种是基于类的。
如果添加上面的属性则使用基于类的cglib的方式,相反,如果没有写或者是false则通过jdk的基于接口的方式生成代理类。
当然,如果本身不是基于接口的,那么会自动使用cglib的方式,在这里很奇怪为什么没有自动走cglib的方式。
如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK 基于接口的代理将起作用。

遗留的问题

spring中context的获取有好几种方式:
ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EntityManager.class);

EntityManager:

@Configuration
@ComponentScan(basePackages = {"com.mitsuhide.*"})
public class EntityManager {
}

@Configuration,@ComponentScan是啥,需要讨论。

你可能感兴趣的:(spring,AOP,Web)