Spring
什么是Spring框架?
Spring框架是个轻量级的Java EE框架。所谓轻量级,是指不依赖于容器就能运行的,并且在运行的时候不会消耗大量的资源,内存,CPU等。Struts、Hibernate也是轻量级的。 Spring的核心是IOC和AOP,所谓IOC是Inversion of Control 的缩写,它是指控制反转模式(也称作依赖注入), 负责创建对象,管理对象,装配对象,配置对象,并且管理这些对象的整个生命周期。而AOP是Aspect Oriented Programming的缩写,面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
spring框架的优点?
(1)低侵入式设计,代码污染极低
(2)独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once,Run Anywhere的承诺。
(3)Spring的DI机制降低了业务对象替换的复杂性,提高了组件之间的解耦
(4)Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用
(5)Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问
(6)Spring并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部
Spring注解
- @Repository:标注数据访问层。(dao层)
- @Service:标注一个业务逻辑层。(service层)
- @Controller:标注一个控制层。 (controller)
- @Component :没有明确的分类,当确定不了分类时,可以使用该注解标注。尽量少使用。
被注解的java类当做Bean实例,Bean实例的名称默认是Bean类的首字母小写,在加上注解之后不要忘记在Spring的配置文件中加上自动扫描哪些包下面的注解哦。
- @Bean 等同于xml配置中的
<beans>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
</beans>
- @Value:为属性注入值。
@Value("Qiqi")
private String name;
//name的值为 Qiqi
- @Autowired:自动装配,默认是根据类型注入,用于替代基于XML配置的自动装配。可用于为类的属性、构造器、方法进行注值 。
- @Resource:相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按byName自动注入。它有两个属性,name和type,name属性为bean的名字,type属性为bean的类型。如果使用name属性,则使用byName的自动注入策略,使用type属性时则使用byType自动注入策略。
- @Qualifier 与 @Autowired配合使用,@Qualifier(“指定加载类的名字”)与@Autowired标注的类进行装配。
关于切面(AOP)相关注解(具体例子详见下面AOP使用注解配置)
- @Aspect 标注一个切面类。
- @PointCut 标注切点 。
- @After 后置通知,在方法执行之后执行
- @Before 前置通知,在方法执行之前执行
- @Around 环绕通知,在方法执行之前与之后执行
- @Scope 创建的 Bean 对象相对于其他 Bean 对象的请求可见范围,默认是单例模式@Scope(value="Singleton")。 相当于xml文件中的
<bean id="XXX" class="com.XXX.XXXXX" scope="XXXX" />
bean的作用域包括:
Singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例, 是默认模式。
Protetype: 每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。
Request: web项目中,对于每次HTTP请求,使用request定义的Bean都将产生一个新实例
Session:web项目中,对于每次HTTP Session,使用session定义的Bean都将产生一个新实例
GlobalSession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例
- @Configuration标注当前类为配置类,相当于xml形式的Spring配置
- @Bean 注解在方法上,标注当前方法的返回值为一个bean。
- @ComponentScan 会自动扫描指定包路径下面的所有@Controller、@Repository、@Service、@Component 的类,属性有: value指定扫描的包,includeFilters包含那些过滤,excludeFilters不包含那些过滤,相当于xml中的
<context:component-scan base-package="main.java">
<context:exclude-filter type="annotation" expression="XX"/>
<context:include-filter type="annotation" expression="XX"/>
</context:component-scan>
- @PostConstruct,标注在方法上,这个方法就会在Bean初始化之后被Spring容器执行。用于访问父类中不可重写的方法或属性。例如当子类想访问父类中标注为final的方法的时候,可以使用该注解,通过super.父类标注为final的方法名就可以访问了。
- @PreDestroy,标注在方法上,这个方法就会在Bean初始化之后被Spring容器执行。其用法同@PostConstruct。和@PostConstruct 区别在于:@PostConstruct注释的方法将在类实例化后调用,而标注了 @PreDestroy 的方法将在类销毁之前调用。
IOC
Spring的核心是IOC和AOP,所谓IOC是Inversion of Control 的缩写,它是指控制反转模式(也称作依赖注入,依赖注入是通过Java反射机制实现的,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中), 负责创建对象,管理对象,装配对象,配置对象,并且管理这些对象的整个生命周期。
BeanFactory与ApplacationContext的区别
IOC中最核心的接口是Beanfactory提供IOC的高级服务,BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。
ApplicationContext接口:ApplicationContext是建立在BeanFactory基础之上提供抽象的面向应用的服务,它由BeanFactory接口派生而来,因而具有BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:
• MessageSource, 提供国际化的消息访问
由于ApplicationContext扩展了MessageResource接口,因而具有消息处理的能力。
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messageTozh</value><!--国际化文件名称messageTozh_zh_CN.properties,名称格式为XX_zh_CN.properties -->
</list>
</property>
</bean>
messageTozh_zh_CN.properties文件内容:
name = \u59d3\u540d{0}
date = \u73b0\u5728\u65f6\u95f4\u662f:{0}
注意:文件中的中文容易出现乱码,要做适当的处理
测试:
@Test
public void returnMessage() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
String name = applicationContext.getMessage("name", new String[] {"琪琪"},Locale.getDefault());
String date = applicationContext.getMessage("date", new Object[]{new Date()},Locale.getDefault());
System.out.println(name + "\n"+date);
}
• 资源访问,如URL和文件 (Resource接口)
- ApplicationContext.getResource 默认在工程的一级目录下寻找资源文件。
@Test
public void Accesspath(){
ApplicationContext applicationContext1 = new ClassPathXmlApplicationContext("applicationContext.xml");
Resource resource = applicationContext1.getResource("classpath:db.properties");
System.out.println("文件是否存在:"+resource.exists());
}
• 事件机制
ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。
ApplicationEvent:容器事件,必须由ApplicationContext发布
ApplicationListener:监听器,可由容器中的任何监听器Bean担任
(1) . Java类继承了ApplicationEvent类,那么该对象即可以作为Spring容器的容器事件。
(2) . 容器事件的监听器类必须实现ApplicationListener接口,实现该接口实现了
onApplicationEvent(ApplicationEvent event)方法:表示每当容器内发生任何事件时,此方法都会被触发。
(3) . Spring中配置一个实现了ApplicationListener的Bean,Spring容器就会把这个Bean当成容器事件的监听器。
(4) . 调用ApplicationContext的publishEvent()方法来主动触发一个容器事件。
以下一个年龄监控例子来说明Spring的事件机制:
//此处省略Student类
package login.event;
import org.springframework.context.ApplicationEvent;
/***
* 容器事件
* @author wq
*
*/
public class AgeEvent extends ApplicationEvent {
private Student student;
public AgeEvent(Student student) {
super(student);
this.student = student;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
package login.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
/***
* 容器事件监听器
* @author wq
*
*/
public class AgeEventListener implements ApplicationListener{
@Override
public void onApplicationEvent(ApplicationEvent evt) {
if(evt instanceof AgeEvent){
AgeEvent ageEvent = (AgeEvent) evt;
Student student = ageEvent.getStudent();
if(student.getAge() > 16 && student.getAge() < 19 ) {
System.out.println(student.getName()+","+student.getAge()+"这个年龄普遍是高中年龄范围");
}
if(student.getAge() <= 22 && student.getAge() >=18){
System.out.println(student.getName()+","+student.getAge()+"这个年龄普遍是大学毕业");
}else if(student.getAge()>23){
System.out.println(student.getName()+","+student.getAge()+"这个年龄超出监控范围");
}
}
}
}
//Spring xml文件配置
<!--事件机制 -->
<bean id="student" class="login.event.Student">
<property name="name">
<value>琪琪</value>
</property>
<property name="age">
<value>27</value>
</property>
</bean>
<!--配置监听器 -->
<bean id="ageEventListener" class="login.event.AgeEventListener"></bean>
//测试
@Test
public void rerturnAgeListener() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) applicationContext.getBean("student");
applicationContext.publishEvent(new AgeEvent(student));
}
Spring还提供了几个内置事件:
- ContextRefreshedEvent:ApplicationContext容器初始化或刷新时触发该事件。
- ContextStartedEvent:当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的start()方法启动ApplicationContext容器时触发该事件。需要停止后重新启动的场合比较常见。
- ContextClosedEvent:当使用ConfigurableApplicationContext接口的close()方法关闭ApplicationContext时触发该事件。
- ContextStoppedEvent:当使用ConfigurableApplicationContext接口的stop()方法使ApplicationContext容器停止时触发该事件。
- RequestHandledEvent:Web相关事件,只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。
• Spring上下文获取
Spring上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
通过ApplicationContextAware加载Spring上下文环境,通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法。
package util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component //如果没有使用注解的方式,使用xml的方式,记得在spring的xml中加入<bean id="springContextUtil" class="XX" />
public class SpringContextUtil implements ApplicationContextAware{
private static ApplicationContext applicationContext;//spring上下文
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
SpringContextUtil.applicationContext=applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
public static <T> T getBean(String name) throws BeansException{
return (T)applicationContext.getBean(name);
}
}
//配置web.xml文件
<!--初始化Spring容器,让Spring容器随Web应用的启动而自动启动 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
然后我们可以通过该方法的getBean()方法得到Spring容器中的对象了。
我们还可以通过 new ClassPathXmlApplicationContext("applicationContext.xml");这种方式来获取Spring上下文环境,但是这种方法通常是用在测试环境中的,在系统不启动的情况下手动初始化Spring上下文再获取对象。在web项目中,系统一旦启动,web服务器会初始化Spring的上下文的,如果使用该方法,所有bean会再被创建一次,会造成重复,系统加载速度慢。
依赖注入的三种方式
- setter注入(主要)
- 接口注入
- 构造方法注入(主要)
Spring管理bean
程序主要是通过Spring容器来访问容器中的Bean,ApplicationContext是Spring容器最常用的接口,该接口有如下两个实现类:
ClassPathXmlApplicationContext: 从类加载路径下搜索配置文件,并根据配置文件来创建Spring容器。
FileSystemXmlApplicationContext: 从文件系统的相对路径或绝对路径下去搜索配置文件,并根据配置文件来创建Spring容器。
public void returnResult() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
LoginManager loginManager = (LoginManager) applicationContext.getBean("loginManager");
loginManager.add();
}
spring创建bean的3种方式
- 构造器创建bean实例,当没有采用构造方式注入bean的时候,spring会去调用无参构造方法来创建bean,因此必须要提供无参构造器。
<!-- 不带参数的构造器 -->
<bean id="login" class="com.flowers.login.beans.LoginBean" > </bean>
<bean id="login" class="com.flowers.login.beans.LoginBean" >
<!-- 创建一个value为琪琪的name -->
<constructor-arg name="name" value="琪琪"></constructor-arg>
</bean>
<!-- 有参构造器 -->
<bean id="login" class="com.flowers.login.beans.LoginBean">
<!-- index表示参数顺序,type为参数类型 value为参数值 -->
<constructor-arg value="琪琪" index="0" type="java.lang.String"></constructor-arg>
<!-- 直接赋值 -->
<constructor-arg value="琪琪" index="1" type="java.lang.String"></constructor-arg>
<!-- ref:通过引用方式赋值 -->
<constructor-arg index = "1" type = "java.lang.String" ref="login"></constructor-arg>
</bean>
- 使用静态工厂方法创建bean实例,class属性必须指定,Spring通过该属性知道由哪个工厂类来创建Bean实例。采用静态工厂方法创建bean时,<bean />元素需要制定两个属性:
class: 该属性的值为静态工厂类的类名。
factory-method: 指定静态工厂的方法来生产bean实例。
<bean id="login" class="com.flowers.login.LoginFactory" factory-method="getStaticFactory"></bean>
- 使用实例工厂方法创建bean实例,配置Bean实例的<bean.../>元素无须class属性,配置实例工厂方法使用factory-bean指定工厂实例。采用实例工厂方法创建Bean的<bean.../>元素时需要指定如下两个属性:
factory-bean: 该属性的值为工厂Bean的id。
factory-method: 指定实例工厂的工厂方法。
<bean id="factory" class="com.flowers.login.LoginFactory"></bean>
<bean id="user4" factory-bean="factory" factory-method="getfactory"></bean>
Spring Bean的生命周期
(1) . 实例化一个bean,就是我们通常干的new
(2) . 根据spring上下文对实例化的bean进行配置,通常就是指IOC注入。
(3) . 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值;
(4) . 如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身;
(5) . 如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(6) . 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
(7) . 如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
(8) . 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;
(9) . 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用DisposableBean的destroy()方法;
(10) . 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
Spring中bean的加载过程
(1)获取配置文件资源;
(2)对获取的xml资源进行一定的处理检验;
(3)处理包装资源;
(4)解析处理包装过后的资源;
(5)加载提取bean并注册(添加到beanDefinitionMap中)。
在Spring框架中共有5种自动装配:
<bean id="login" class="com.flowers.login.beans.LoginBean" autowire="XX"> </bean>
autowire的值有:
(1)no:在该设置下自动装配是关闭的,开发者需要自行在bean定义中用标签明确的设置依赖关系。
(2)byName:根据setter方法名进行自动装配。Spring容器查找容器中全部Bean,找出其id与setter方法名去掉set前缀,并小写首字母后同名的Bean来完成注入。如果找到的话,就装配这个属性,如果没找到的话就报错。
(3)byType:该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
(4)constructor:构造器的自动装配和byType模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
(5)default:表示默认采用上一级标签的自动装配的取值。如果存在多个配置文件的话,那么每一个配置文件的自动装配方式都是独立的。
注:有多个类型的bean则无法完成自动装配
<!--注入一般属性,spring注入方式一般有属性注入,构造方法注入,set注入 -->
<bean id="loginDaoImpl" class="com.flowers.login.dao.LoginDaoImpl"></bean>
<bean id="loginManager" class="com.flowers.login.impl.LoginManager">
<property name="loginDao" ref="loginDaoImpl"></property>
</bean>
当一个Bean既使用自动装配依赖,又使用ref显式指定依赖时,则显式指定的依赖覆盖自动装配依赖;对于大型的应用,不鼓励使用自动装配。虽然使用自动装配可减少配置文件的工作量,但大大将死了依赖关系的清晰性和透明性。依赖关系的装配依赖于源文件的属性名和属性类型,导致Bean与Bean之间的耦合降低到代码层次,不利于高层次解耦。
AOP
AOP是Aspect Oriented Programming的缩写,面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP的基本概念
AOP常用有切点(Pointcut)、连接点(Join point)、切面(Aspect)、引入(Introduction)、织入(Weaving)、通知(Advice)等。
- 切点(Pointcut):选择一组相关连接点的模式,即可以认为连接点的集合,在AOP中表示为“在哪里干的集合”;
- 连接点(Join point):程序执行过程中明确的点,如连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等,在springMVC中,连接点总是方法的抛出。 Spring只支持方法执行连接点,在AOP中表示为“在哪里干”;
- 切面(Aspect):切面用于组织多个Advice,Advice放在切面定义中。在Spring中可以使用Schema和@AspectJ方式进行组织实现;在AOP中表示为“在哪干和干什么集合”;切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。
- 引入(Introduction):也称为内部类型声明,将方法或字段添加到被处理的类中。Spring允许引入新的接口(必须对应一个实现)到任何被处理的对象(目标对象)中, 在AOP中表示为“干什么(引入什么)”;
- 织入(Weaving):织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期、类装载期、运行期进行。在运行时完成织入。
- 通知(Advice):在连接点上执行的行为,通知提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段;包括前置通知(before advice)、后置通知(after advice)、环绕通知(around advice),在Spring中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入通知;在AOP中表示为“干什么”;
对Spring AOP的配置
对于Spring AOP的配置有两种方法,一种是使用注解,另一种是xml文件配置。
- 使用注解配置
package test;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspectForAnnotation {
/**
* 前置通知
*/
@Before("execution(public * login.manager.LoginManager.add())")
public void before(){
System.out.println("注解前置通知....");
}
/**
* 成功返回后的通知
*
*/
@AfterReturning(value="execution(public * login.manager.LoginManager.add())",returning="returnVal")
public void afterReturning(Object returnVal){
System.out.println("注解成功返回后的通知...."+returnVal);
}
/**
* 环绕通知
* @param joinPoint 可用于执行切点的类
* @return
* @throws Throwable
*/
@Around("execution(public * login.manager.LoginManager.add())")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("注解环绕通知前....");
Object obj= (Object) joinPoint.proceed();
System.out.println("注解环绕通知后....");
return obj;
}
/**
* 抛出通知
* @param e
*/
@AfterThrowing(value="execution(public * login.manager.LoginManager.add())",throwing="e")
public void afterThrowable(Throwable e){
System.out.println("注解出现异常:msg="+e.getMessage());
}
/**
* 后置通知,不管被通知的方法是否执行成功
*/
@After("execution(public * login.manager.LoginManager.add())")
public void after(){
System.out.println("注解后置通知,不管被通知的方法是否被执行成功....");
}
}
xml配置:
<aop:aspectj-autoproxy /> <!--使用AOP注解 -->
<!--定义切面类 -->
<bean id="myAspect" class="test.MyAspectForAnnotation"></bean>
<bean id="loginDaoImpl" class="login.dao.LoginDaoImpl"></bean>
<bean id="loginManager" class="login.manager.LoginManager">
<property name="loginDao" ref="loginDaoImpl"></property>
</bean>
测试类:
@Test
public void returnResultForAnnotation() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("AOPforAnnotation.xml");
ILoginManager iloginManager = (ILoginManager) applicationContext.getBean("loginManager");
iloginManager.add();
}
- 使用xml文件配置
<bean id="myAspect" class="AOP方法路径"></bean>
<aop:config>
<aop:pointcut expression="execution(方法类型 * 方法路径.方法名()")" id="servicePointcut"/> // 配置切点
<aop:aspect id="logAspect" ref="myAspect"> //配置切面
<aop:before method="before" pointcut-ref="servicePointcut" /> //通知
</aop:aspect>
</aop:config>
例如:
package test;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspectForXml {
/**
* 前置通知
*/
public void before(){
System.out.println("前置通知....");
}
/**
* 成功返回后的通知
*
*/
public void afterReturning(Object returnVal){
System.out.println("成功返回后的通知...."+returnVal);
}
/**
* 环绕通知
* @param joinPoint 可用于执行切点的类
* @return
* @throws Throwable
*/
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前....");
Object obj= (Object) joinPoint.proceed();
System.out.println("环绕通知后....");
return obj;
}
/**
* 抛出通知
* @param e
*/
public void afterThrowable(Throwable e){
System.out.println("出现异常:msg="+e.getMessage());
}
/**
* 后置通知,不管被通知的方法是否执行成功
*/
public void after(){
System.out.println("后置通知,不管被通知的方法是否被执行成功....");
}
}
xml文件配置:
<bean id="loginDaoImpl" class="login.dao.LoginDaoImpl"></bean>
<bean id="loginManager" class="login.manager.LoginManager">
<property name="loginDao" ref="loginDaoImpl"></property>
</bean>
<!--AOP xml配置 -->
<!--定义切面 -->
<bean id="myAspect" class="test.MyAspectForXml"></bean>
<!--配置切面 -->
<aop:config>
<!--定义切点函数 -->
<aop:pointcut expression="execution(public * login.manager.LoginManager.add())" id="addPointcut"/>
<aop:aspect ref="myAspect" order="0">
<!--前置通知 -->
<aop:before method="before" pointcut-ref="addPointcut" />
<!--成功返回后的通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="addPointcut" returning="returnVal"/>
<!--环绕通知 -->
<aop:around method="around" pointcut-ref="addPointcut"/>
<!--抛出通知 -->
<aop:after-throwing method="afterThrowable" pointcut-ref="addPointcut" throwing="e"/>
<!--后置通知,不管被通知的方法是否被执行成功 -->
<aop:after method="after" pointcut-ref="addPointcut" />
</aop:aspect>
</aop:config>
注意:after-returning和after-throwing需要加入参数。returning=“XX”和throwing=“XX”,order越小越是最先执行,最先执行的最后结束。
测试类:
package test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import login.manager.ILoginManager;
public class LoginTest {
@Test
public void returnResult() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
ILoginManager iloginManager = (ILoginManager) applicationContext.getBean("loginManager");
iloginManager.add();
}
}
AOP的动态代理
1、jdk动态代理
2、cglib动态代理
Spring在选择用JDK动态代理还是CGLiB动态代理的依据:
(1)当Bean实现接口时,Spring就会用JDK的动态代理
(2)当Bean没有实现接口时,Spring使用CGlib是实现
如果是单例,则可以选择CGlib动态代理,如果是多列则选择JDK动态代理,因为JDK在创建代理对象时的性能要高于CGLib代理,而生成代理对象的运行性能却比CGLib的低。