切面(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是啥,需要讨论。