spring小结一
来源:互联网 发布:网络打印机图标灰色 编辑:程序博客网 时间:2024/05/29 09:38
一、概述
1. Spring是一个开源框架,其目的是为了解决企业应用开发的复杂性.
2. Spring功能:使用基本的JavaBean代替EJB,并提供更多的企业应用功能.
3. 简单说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架.
二、Spring的jar包和配置文件
1.Spring的jar包
(1)spring的核心类库在spring文档的dist下.
(2)引入的第三方类库在spring文档的lib下.
(3)常用第三方类库
* 如果使用了切面编程(AOP),需要 lib/aspectj/aspectjweaver.jar和aspectjrt.jar
lib/cglib/cglib-nodep-2.1_3.jar
* 如果使用了@Resource/@PostConstruct/@PreDestroy等注解,需要
lib/j2ee/common-annotations.jar
2.Spring的配置文件
默认是applicationContext.xml文件.
但实际工程中,一般建立多个xml文件,在applicationContext.xml中引入.
三、Spring的基本功能
1.SpringIOC
* spring的控制反转:把对象的创建、初始化、销毁等工作交给spring容器来做,由spring容器控制对象的生命周期.
* spring容器的启动:
(1)在类路径下寻找配置文件来实例化容器(常用):
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
这种方式需要将spring配置文件放到当前项目的classpath路径下.
(2)在文件系统路径下寻找配置文件来实例化容器:
ApplicationContext ac = new FileSystemXmlApplicationContext(new String[]{"d:\\beans.xml"});
* 配置文件可以有多个,通过String数组传入.
2.别名
* 使用别名可以达到,在一个地方命名,多个地方使用不同名字的效果.
<beans>
<alias name="person" alias="p"/>
<bean name="person" class="com.liu.domain.Person"/>
</beans>
3.Spring容器内部对象的创建
(1)使用类构造器实例化(默认是无参数的)
<bean id="personService" class="com.liu.bean.impl.PersonServiceImpl"/>
(2)使用静态工厂方法实例化(简单工厂模式)
<bean id="personService" class="com.liu.factory.PersonServiceFactory" factory-method="createPersonService"/>
工厂类:
public class PersonServiceFactory {
public static PersonService createPersonService(){
return new PersonServiceImpl();
}
}
(3)注意,初始化bean时机
* Spring默认在启动时将所有singleton bean提前进行实例化.即作为初始化的一部分.
* ApplicationContext会自动创建并配置所有的singleton bean.
* Lazy-init="false"时,spring容器将在启动的时候报错(可以及时发现错误)
* Lazy-init="true"时,spring容器将在调用该类的时候出错.
4.Bean的作用域(scope属性)
(1)singleton(默认值)
* 在每个spring IoC容器中,一个bean定义只有一个对象实例,即是单例的.
* 默认情况下Bean节点的lazy-init为false,即容器启动就初始化bean,如果想延迟,可改为true
* 如果相对所有bean都延迟初始化,可以在根节点Beans设置default-lazy-init="true"
例如:<beans default-lazy-init="true"..>
(2)prototype
* 允许bean可以被多次实例化(使用一次就创建一个实例).
* spring不能对prototype bean的整个生命周期负责,这就意味着清楚prototype作用域的对象
并释放任何prototype bean所持有的昂贵资源都是客户端的责任
(3)Request
在一次Http请求中,一个bean定义对应一个实例;
即每次Http请求将会有各自的bean实例,它们依据某个bean定义创建而成.
该作用域仅在基于web的Spring ApplicationContext情形下有效.
(4)Session
在一个Http Session中,一个bean定义对应一个实例,该作用域仅在基于web的Spring ApplicationContext情形下有效.
(5)Global session
再一个全局的Http Session中,一个bean定义对应一个实例.
典型情况下,仅在使用portlet context的时候有效.
该作用域仅在基于web的Spring ApplicationContext情形下有效.
(6)指定Bean的初始化方法和销毁方法
* Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方.
<bean id=“foo” class=“...Foo”
init-method=“setup”
destory-method=“teardown”/>
* 当foo被载入到Spring容器中时调用init-method方法.当foo从容器中删除时调用destory-method(scope = singleton有效)
5.依赖注入(DI)
(1)使用构造器注入
* 通过xml的方式注入:
A:通过参数的顺序:
<constructor-arg index="0">
<value>张三</value>
</constructor-arg>
<constructor-arg index="1">
<value>56</value>
</constructor-arg>
B:通过参数的类型:
<constructor-arg type="java.lang.Integer">
<value>56</value>
</constructor-arg>
<constructor-arg type="java.lang.String">
<value>张三</value>
</constructor>
(2)使用属性setting方法进行注入
* 通过xml的方式注入:
A:简单Bean的注入:
简单Bean包括:包装类型和String
<bean id="personService" class="com.liu.service.impl.PersonServiceImpl">
<!-- 基本类型,String类型 -->
<property name="age" value="20"/>
<property name="name" value="张三"/>
</bean>
B:引用其它Bean
<bean id="person" class="com.itcast.bean.Person" />
<bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">
<property name="person" ref="person" />
</bean>
(3)装配list集合
<property name="lists">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
(4)装配set集合
<property name="sets">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
(5)装配map
<property name="maps">
<map>
<entry key="01">
<value>map01</value>
</entry>
<entry key="02">
<value>map02</value>
</entry>
</map>
</property>
(6)装配Properties
<property name="props">
<props>
<prop key="01">prop1</prop>
<prop key="02">prop2</prop>
</props>
</property>
6.注解注入
(1)步骤
A.在配置文件中,引入context命名空间(星号的)
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring- beans-2.5.xsd
***** http://www.springframework.org/schema/context
***** http://www.springframework.org/schema/context/spring-context-2.5.xsd">
B.在配置文件中加入context:annotation-config标签
<context:annotation-config/>
此配置隐式注册了多个对注释进行解析处理的处理器.
AutowiredAnnotationBeanPostProcessor,
CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,
RequiredAnnotationBeanPostProcessor
注:@Resource注解在spring文档的lib\j2ee\common-annotations.jar
(2)@Autowired
* @Autowired与@Resource区别:
@Autowired默认按类型装配
@Resource默认按名称装配,当找不到与名称匹配的bean时,才会按类型装配.
* @Autowired默认情况下要求依赖对象必须存在,如果允许为null值,可设置它required属性为false
@Autowired(required=false)
private PersonDao personDao; //用于字段上
@Autowired(required=false)
public void setPersonDao(PersonDao personDao){ //用于属性set方法上
this.personDao = personDao;
}
(3)@Qualifier
如果向按名称装配,可以结合@Qualifier注解一起使用.
@Autowired@Qualifier("personDao")
private PersonDao personDao; //用于字段上
@Autowired
public void setPersonDao(@Qualifier("personDao")PersonDao personDao){
this.personDao = personDao;
}
(4)@Resource
* 它也可标注在字段或属性的setter方法上.
* 如果没有指定name属性,会先按照名称寻找依赖对象,如果找不到,会退回到按类型装配,而指定了name属性,则只能按名称装配.
(5)@PostConstruct和@PreDestroy
@PostConstruct:指定bean的初始化方法.
@PreDestroy:指定bean的销毁方法.
7.扫描注入
在一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便.
spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了@Component、@Service、
@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理.
(1) 步骤
* 引入context命名空间,
和注解注入引入的命名空间是一样的.
* 在配置文件中添加context:component-scan标签
<context:component-scan base-package="com.liu"/>
其中base-package为需要扫描的包(包含子包)
(2)功能
@Service 用于标注业务层组件
@Controller 用于标注控制层组件(如struts中的action)
@Repository 用于标注数据访问组件,即DAO组件
@Component 泛指组件,当组件不好归类时,可以用这个注解标注.
8.spring中的继承
Person类:
public class Person{
private String sex;
//..setter,getter方法略
}
student类:
public class Student extends Person{
..
}
配置文件:
<bean id="person" class="com.liu.Person">
<property name="sex">
<value>man</value>
</property>
</bean>
<bean id="student" class="com.liu.Student" parent="person"/>
配置文件中,parent属性为student在容器中继承person,如果去掉person是不行的.
四、面向切面编程
1.代理模式
总结:jdk动态代理必须具备四个条件:目标接口、目标类、拦截器、代理类
* 因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有.
* 利用JDKProxy方式必须有接口的存在
* invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型.
(2)CGLIB做代理
* 用CGlib生成代理类是目标类的子类
* 用CGlib生成代理类不需要接口
* 用CGlib生成的代理类重写了父类的各个方法
* 拦截器中的intercept方法内容正好就是代理类中的方法体
(3)spring的两种代理方式(默认是jdk动态代理)
* 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理.
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
* 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在.
缺点:因为没有使用接口,所以系统的耦合性相对要差.
2.AOP编程
(1)概念
* Aspect(切面):比如说事务、权限等,与业务逻辑没有关系的部分.
* joinpoint(连接点):目标类的目标方法,由客户端在调用的时候决定
* Pointcut(切入点):指我们要对那些拦截的方法的定义,被纳入spring aop中的目标类的方法
* Advice(通知):指拦截到joinpoint之后要做的事情就是通知.
分为,前置通知、后置通知、异常通知、最终通知、环绕通知.
* Target(目标对象):代理的目标对象
* Weaving(织入)pid=11&gid=1:指把切面应用到目标对象来创建新的代理对象的过程.
切面在指定的连接点织入到目标对象.
(2)对应JDKProxy代理中的概念
SpringAop JDKProxy代理
目标对象 目标对象
切面 拦截器类
通知 拦截器类中的方法
切入点 被拦截到的目标类中方法的集合
连接点 在客户端调用的方法(目标类目标方法)
AOP代理 代理类
织入 代理类的代理方法生成的过程
(3)AOP实现的两种模式
* xml形式
* 前置通知:
<aop:before method="checkSecurity" pointcut-ref="perform" />
* method="checkSecutiry":表示把切面(security)中checkSecurity方法定义为前置通知
* pointcut-ref="perform":把切入点应用到通知.
* 前置拦截的类必须实现MethodBeforeAdvice接口,实现其中的before方法
* 后置通知:
<aop:after-returning method="checkSecurity" pointcut-ref="perform" returning="val" />
* return="val" 通知里可以有返回参数,这个参数只能决定通知里能不能拿到方法的返回值,和客户端没关系.
* 在执行目标类的目标方法中遇到异常,则不执行后置通知.
* 后置拦截的类必须实现AfterReturningAdvice接口,实现其中的afterReturning方法.
* 在拦截器中的方法要和checkSecurity方法一样,有两个参数:
JoinPoint point : 可以获得目标方法和参数值
Object val :这里的名字要和return="val"中保持一致,指的是方法的返回值
* 最终通知:
<aop:after method="checkSecurity" pointcut-ref="perform" />
* 注意:最终通知不受异常影响,即不论目标方法执行的过程中是否抛出异常,最终通知都将执行.
* 环绕通知:
<aop:around method="checkSecurity" pointcut-ref="perform" />
* 前后拦截的类必须实现MethodInterceptor接口,实现其中的invoke方法.
* 异常通知:
<aop:after-throwing method="checkSecurity" pointcut-ref="perform" throwing="ex"/>
* 其中throwing指定了传递异常的参数名称
* 在异常通知中(拦截器)中,必须是checkSecurity方法
方法中有两个参数:
JoinPoint point:可以获得方法的名称、参数
Throwable ex : 利用ex.getMessage()可以获得异常信息
* 注解形式
为了在spring配置中使用@AspectJ切面,首先必须启用Spring对@AspectJ切面配置的支持,并确保自动代理
1. Spring是一个开源框架,其目的是为了解决企业应用开发的复杂性.
2. Spring功能:使用基本的JavaBean代替EJB,并提供更多的企业应用功能.
3. 简单说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架.
二、Spring的jar包和配置文件
1.Spring的jar包
(1)spring的核心类库在spring文档的dist下.
(2)引入的第三方类库在spring文档的lib下.
(3)常用第三方类库
* 如果使用了切面编程(AOP),需要 lib/aspectj/aspectjweaver.jar和aspectjrt.jar
lib/cglib/cglib-nodep-2.1_3.jar
* 如果使用了@Resource/@PostConstruct/@PreDestroy等注解,需要
lib/j2ee/common-annotations.jar
2.Spring的配置文件
默认是applicationContext.xml文件.
但实际工程中,一般建立多个xml文件,在applicationContext.xml中引入.
三、Spring的基本功能
1.SpringIOC
* spring的控制反转:把对象的创建、初始化、销毁等工作交给spring容器来做,由spring容器控制对象的生命周期.
* spring容器的启动:
(1)在类路径下寻找配置文件来实例化容器(常用):
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
这种方式需要将spring配置文件放到当前项目的classpath路径下.
(2)在文件系统路径下寻找配置文件来实例化容器:
ApplicationContext ac = new FileSystemXmlApplicationContext(new String[]{"d:\\beans.xml"});
* 配置文件可以有多个,通过String数组传入.
2.别名
* 使用别名可以达到,在一个地方命名,多个地方使用不同名字的效果.
<beans>
<alias name="person" alias="p"/>
<bean name="person" class="com.liu.domain.Person"/>
</beans>
3.Spring容器内部对象的创建
(1)使用类构造器实例化(默认是无参数的)
<bean id="personService" class="com.liu.bean.impl.PersonServiceImpl"/>
(2)使用静态工厂方法实例化(简单工厂模式)
<bean id="personService" class="com.liu.factory.PersonServiceFactory" factory-method="createPersonService"/>
工厂类:
public class PersonServiceFactory {
public static PersonService createPersonService(){
return new PersonServiceImpl();
}
}
(3)注意,初始化bean时机
* Spring默认在启动时将所有singleton bean提前进行实例化.即作为初始化的一部分.
* ApplicationContext会自动创建并配置所有的singleton bean.
* Lazy-init="false"时,spring容器将在启动的时候报错(可以及时发现错误)
* Lazy-init="true"时,spring容器将在调用该类的时候出错.
4.Bean的作用域(scope属性)
(1)singleton(默认值)
* 在每个spring IoC容器中,一个bean定义只有一个对象实例,即是单例的.
* 默认情况下Bean节点的lazy-init为false,即容器启动就初始化bean,如果想延迟,可改为true
* 如果相对所有bean都延迟初始化,可以在根节点Beans设置default-lazy-init="true"
例如:<beans default-lazy-init="true"..>
(2)prototype
* 允许bean可以被多次实例化(使用一次就创建一个实例).
* spring不能对prototype bean的整个生命周期负责,这就意味着清楚prototype作用域的对象
并释放任何prototype bean所持有的昂贵资源都是客户端的责任
(3)Request
在一次Http请求中,一个bean定义对应一个实例;
即每次Http请求将会有各自的bean实例,它们依据某个bean定义创建而成.
该作用域仅在基于web的Spring ApplicationContext情形下有效.
(4)Session
在一个Http Session中,一个bean定义对应一个实例,该作用域仅在基于web的Spring ApplicationContext情形下有效.
(5)Global session
再一个全局的Http Session中,一个bean定义对应一个实例.
典型情况下,仅在使用portlet context的时候有效.
该作用域仅在基于web的Spring ApplicationContext情形下有效.
(6)指定Bean的初始化方法和销毁方法
* Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方.
<bean id=“foo” class=“...Foo”
init-method=“setup”
destory-method=“teardown”/>
* 当foo被载入到Spring容器中时调用init-method方法.当foo从容器中删除时调用destory-method(scope = singleton有效)
5.依赖注入(DI)
(1)使用构造器注入
* 通过xml的方式注入:
A:通过参数的顺序:
<constructor-arg index="0">
<value>张三</value>
</constructor-arg>
<constructor-arg index="1">
<value>56</value>
</constructor-arg>
B:通过参数的类型:
<constructor-arg type="java.lang.Integer">
<value>56</value>
</constructor-arg>
<constructor-arg type="java.lang.String">
<value>张三</value>
</constructor>
(2)使用属性setting方法进行注入
* 通过xml的方式注入:
A:简单Bean的注入:
简单Bean包括:包装类型和String
<bean id="personService" class="com.liu.service.impl.PersonServiceImpl">
<!-- 基本类型,String类型 -->
<property name="age" value="20"/>
<property name="name" value="张三"/>
</bean>
B:引用其它Bean
<bean id="person" class="com.itcast.bean.Person" />
<bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">
<property name="person" ref="person" />
</bean>
(3)装配list集合
<property name="lists">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
(4)装配set集合
<property name="sets">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
(5)装配map
<property name="maps">
<map>
<entry key="01">
<value>map01</value>
</entry>
<entry key="02">
<value>map02</value>
</entry>
</map>
</property>
(6)装配Properties
<property name="props">
<props>
<prop key="01">prop1</prop>
<prop key="02">prop2</prop>
</props>
</property>
6.注解注入
(1)步骤
A.在配置文件中,引入context命名空间(星号的)
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring- beans-2.5.xsd
***** http://www.springframework.org/schema/context
***** http://www.springframework.org/schema/context/spring-context-2.5.xsd">
B.在配置文件中加入context:annotation-config标签
<context:annotation-config/>
此配置隐式注册了多个对注释进行解析处理的处理器.
AutowiredAnnotationBeanPostProcessor,
CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,
RequiredAnnotationBeanPostProcessor
注:@Resource注解在spring文档的lib\j2ee\common-annotations.jar
(2)@Autowired
* @Autowired与@Resource区别:
@Autowired默认按类型装配
@Resource默认按名称装配,当找不到与名称匹配的bean时,才会按类型装配.
* @Autowired默认情况下要求依赖对象必须存在,如果允许为null值,可设置它required属性为false
@Autowired(required=false)
private PersonDao personDao; //用于字段上
@Autowired(required=false)
public void setPersonDao(PersonDao personDao){ //用于属性set方法上
this.personDao = personDao;
}
(3)@Qualifier
如果向按名称装配,可以结合@Qualifier注解一起使用.
@Autowired@Qualifier("personDao")
private PersonDao personDao; //用于字段上
@Autowired
public void setPersonDao(@Qualifier("personDao")PersonDao personDao){
this.personDao = personDao;
}
(4)@Resource
* 它也可标注在字段或属性的setter方法上.
* 如果没有指定name属性,会先按照名称寻找依赖对象,如果找不到,会退回到按类型装配,而指定了name属性,则只能按名称装配.
(5)@PostConstruct和@PreDestroy
@PostConstruct:指定bean的初始化方法.
@PreDestroy:指定bean的销毁方法.
7.扫描注入
在一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便.
spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了@Component、@Service、
@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理.
(1) 步骤
* 引入context命名空间,
和注解注入引入的命名空间是一样的.
* 在配置文件中添加context:component-scan标签
<context:component-scan base-package="com.liu"/>
其中base-package为需要扫描的包(包含子包)
(2)功能
@Service 用于标注业务层组件
@Controller 用于标注控制层组件(如struts中的action)
@Repository 用于标注数据访问组件,即DAO组件
@Component 泛指组件,当组件不好归类时,可以用这个注解标注.
8.spring中的继承
Person类:
public class Person{
private String sex;
//..setter,getter方法略
}
student类:
public class Student extends Person{
..
}
配置文件:
<bean id="person" class="com.liu.Person">
<property name="sex">
<value>man</value>
</property>
</bean>
<bean id="student" class="com.liu.Student" parent="person"/>
配置文件中,parent属性为student在容器中继承person,如果去掉person是不行的.
四、面向切面编程
1.代理模式
(1)JDK动态代理
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class JDKProxy implements InvocationHandler {private Object targetObject; //代理的目标对象public Object createProxyInstance(Object targetObject) {this.targetObject = targetObject;//第一个参数设置代码使用的类加载器,一般采用跟目标类相同的类加载器//第二个参数设置代理类实现的接口跟目标类使用相同的接口//第三个参数设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("代理类实例" + proxy.getClass());System.out.println("方法名称" + method.getName());if(args!=null && args.length>0) { //方法的参数值for(int i=0; i<args.length; i++) {System.out.println("方法参数值" + args[i].toString());}Object returnvalue = null; //定义方法的返回值,没有返回值时是nullreturnvalue = method.invoke(this.targetObject, args);//调用目标对象的方法System.out.println("方法的返回值" + returnvalue);return returnvalue;}return null;}}
总结:jdk动态代理必须具备四个条件:目标接口、目标类、拦截器、代理类
* 因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有.
* 利用JDKProxy方式必须有接口的存在
* invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型.
(2)CGLIB做代理
* 用CGlib生成代理类是目标类的子类
* 用CGlib生成代理类不需要接口
* 用CGlib生成的代理类重写了父类的各个方法
* 拦截器中的intercept方法内容正好就是代理类中的方法体
//代码示例:需要添加cglib的jar包,可以在spring文档的lib下找到import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CglibProxy implements MethodInterceptor{private Object targetObject; //代理的目标对象//创建目标对象的代理对象public Object createProxyInstance(Object targetObject) {this.targetObject = targetObject;Enhancer enhancer = new Enhancer(); //该类用于生成代理对象enhancer.setSuperclass(this.targetObject.getClass()); //设置父类enhancer.setCallback(this); //设置回调对象为本身return enhancer.create(); //创建代理对象}/* obj 目标对象代理类的实例 * method 代理实例上调用父类方法的Method实例 * args 传入到代理实例上方法参数值的对象数组 * methodProxy 使用它调用父类的方法 */@Overridepublic Object intercept(Object obj, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {System.out.println("代理类" + obj.getClass());System.out.println("方法名称" + method.getName());if(args!=null && args.length>0) {//方法的参数值for(int i=0; i<args.length; i++) {System.out.println("方法参数" + args[i]);}Object returnvalue = null;//方法的返回值,无返回类型时,为nullreturnvalue = methodProxy.invoke(this.targetObject, args);//调用目标对象的方法System.out.println("方法的返回值" + returnvalue);return returnvalue;}return null;}}
(3)spring的两种代理方式(默认是jdk动态代理)
* 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理.
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
* 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在.
缺点:因为没有使用接口,所以系统的耦合性相对要差.
2.AOP编程
(1)概念
* Aspect(切面):比如说事务、权限等,与业务逻辑没有关系的部分.
* joinpoint(连接点):目标类的目标方法,由客户端在调用的时候决定
* Pointcut(切入点):指我们要对那些拦截的方法的定义,被纳入spring aop中的目标类的方法
* Advice(通知):指拦截到joinpoint之后要做的事情就是通知.
分为,前置通知、后置通知、异常通知、最终通知、环绕通知.
* Target(目标对象):代理的目标对象
* Weaving(织入)pid=11&gid=1:指把切面应用到目标对象来创建新的代理对象的过程.
切面在指定的连接点织入到目标对象.
(2)对应JDKProxy代理中的概念
SpringAop JDKProxy代理
目标对象 目标对象
切面 拦截器类
通知 拦截器类中的方法
切入点 被拦截到的目标类中方法的集合
连接点 在客户端调用的方法(目标类目标方法)
AOP代理 代理类
织入 代理类的代理方法生成的过程
(3)AOP实现的两种模式
* xml形式
<!-- 在spring中配置文件中声明切面 --> <bean id="security" class="com.liu.aop.before.Security" /> <!-- 在spring中配置文件中声明目标类 --><bean id="userManager" class="com.liu.aop.before.UserManagerImpl"/><!-- 定义切面、切入点、通知--><aop:aspect id="securityid" ref="security"><aop:pointcut id="perform" expression="execution(* com.liu.aop.before.UserManagerImpl.save*(..))"/><!--定义前置通知--><aop:before method="checkSecurity" pointcut-ref="perform" /></aop:aspect><!--定义切入点 ,让通知拦截到com.liu.aop.before.UserManagerImpl中以save开始的方法* 使用切入点指示符execution : 匹配方法执行的连接点,这是你将会用到的Spring的最主要的切入点指示符。* execution切入点指示符表达式如下:例如:execution("public * com.liu.UserManagerImpl.*(..) throws Exception")execution(modifiers-pattern? 方法的修饰符模式:不是必须的ret-type-pattern:返回类型模式:必须的declaring-type-pattern?: 路径模式,不是必须的.* 方法所在类的路径name-pattern:方法的名称 必须的*表示类中所有的方法"save*"表示类中以save开始的方法(param-pattern):参数模式,必须的* ():匹配了一个不接受任何参数的方法* (..):匹配了一个接受任意数量参数的方法.* 模式(*)匹配了一个接受一个任何类型的参数的方法* 模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个必须是String类型throws-pattern? : 异常模式,抛出的异常 不是必须的示例:* 任意公共方法的执行:execution(public * * (..))* 任何一个名字以set开始的方法的执行:execution(* set*(..))* AccountService接口定义的任意方法的执行:execution(* com.liu.service.AccountService.*(..))* 在service包中定义的任意方法的执行:execution(* com.liu.service..*(..))* 在service包或其子包中定义的任意方法的执行:execution(* com.liu.service..*.*(..)) -->
* 前置通知:
<aop:before method="checkSecurity" pointcut-ref="perform" />
* method="checkSecutiry":表示把切面(security)中checkSecurity方法定义为前置通知
* pointcut-ref="perform":把切入点应用到通知.
* 前置拦截的类必须实现MethodBeforeAdvice接口,实现其中的before方法
* 后置通知:
<aop:after-returning method="checkSecurity" pointcut-ref="perform" returning="val" />
* return="val" 通知里可以有返回参数,这个参数只能决定通知里能不能拿到方法的返回值,和客户端没关系.
* 在执行目标类的目标方法中遇到异常,则不执行后置通知.
* 后置拦截的类必须实现AfterReturningAdvice接口,实现其中的afterReturning方法.
* 在拦截器中的方法要和checkSecurity方法一样,有两个参数:
JoinPoint point : 可以获得目标方法和参数值
Object val :这里的名字要和return="val"中保持一致,指的是方法的返回值
* 最终通知:
<aop:after method="checkSecurity" pointcut-ref="perform" />
* 注意:最终通知不受异常影响,即不论目标方法执行的过程中是否抛出异常,最终通知都将执行.
* 环绕通知:
<aop:around method="checkSecurity" pointcut-ref="perform" />
* 前后拦截的类必须实现MethodInterceptor接口,实现其中的invoke方法.
* 异常通知:
<aop:after-throwing method="checkSecurity" pointcut-ref="perform" throwing="ex"/>
* 其中throwing指定了传递异常的参数名称
* 在异常通知中(拦截器)中,必须是checkSecurity方法
方法中有两个参数:
JoinPoint point:可以获得方法的名称、参数
Throwable ex : 利用ex.getMessage()可以获得异常信息
* 注解形式
为了在spring配置中使用@AspectJ切面,首先必须启用Spring对@AspectJ切面配置的支持,并确保自动代理
<beans ...><!-- 启用spring对@AspectJ的支持 --><aop:aspectj-autoproxy/><!-- 声明切面对象 --><bean id="security" class="com.liu.service.Security"/><!-- 创建接口实现类对象 --><bean id="userManager" class="com.liu.service.UserManagerImpl"/></beans>// 前置通知/* @Aspectj是按照类型匹配 * @Pointcut用于声明切入点 *在@AspectJ注解风格的aop中,一个切入点签名通过一个普通的方法来定义 * 1.作为切入点签名的方法必须返回void类型 *2.方法没有参数用private修饰 *3.方法体为空 *切入点表达式的写法 *execution(..)表示匹配方法执行的连接点 *1."*"表示方法的返回类型任意 * 2.com.liu.service..* 表示service包及其子包中所有的类 * 3.save* 表示类中所有以save开头的方法 * 4.(..)表示参数是任意数量 *@Before 前置通知,在方法调用前执行 *userManagerPointcut() 表示前面定义的切入点 *args 限定匹配特定的连接点(使用spring AOP 的时候方法的执行),其中参数是指定类型的实例 * username1,psw 参数表示指定类型的实例 *参数名称必须与通知的参数名称一致 *通知参数的类型必须与目标对象参数的类型一致,如不一致,则拦截不到 */@Aspectpublic class Security {@Pointcut("execution(* com.liu.service..*.save*(..))")private void userManagerPointcut(){}@Before("userManagerPointcut() && args(username1,psw)")public void checkSecurity(String username1, String psw){System.out.println("安全检查"+username1+" "+psw);}}// 后置通知@Aspectpublic class Security {@Pointcut("execution(* com.liu.service..*.save*(..))")private void userManagerPointcut(){}@AfterReturning(pointcut="userManagerPointcut()",returning="value")public void checkSecurity(String value) {System.out.println("安全检查"+value);}}// 异常通知@Aspectpublic class Security {@Pointcut("execution(* com.liu.service..*.save*(..))")private void userManagerPointcut(){}@AfterThrowing(pointcut="userManagerPointcut()",throwing="ex")public void checkSecurity(Exception ex) {System.out.println("安全检查" + ex);}}// 最终通知@Aspectpublic class Security {@Pointcut("execution(* com.liu.service..*.save*(..))")private void userManagerPointcut(){}@After("userManagerPointcut()")public void checkSecurity(Exception ex) {System.out.println("安全检查");}}// 环绕通知@Aspectpublic class Security {@Pointcut("execution(* com.liu.service..*.save*(..))")private void userManagerPointcut(){}@Around("userManagerPointcut()")public Object checkSecurity(ProceedingJoinPoint point)throw Throwable {System.out.println("方法的名称" + point.getSignature().getName());System.out.println("测试参数对象是否为空" + point.getArgs().toString());if(point.getArgs().length > 0) {for(int i=0; i<point.getArgs().length; i++) {System.out.println("方法的参数值" + point.getArgs()[i]);}}Object returnvalue = null; //调用方法的返回值,方法无返回值时是nullreturnvalue=point.proceed(); //调用目标对象方法System.out.println("returnvalue" + returnvalue);System.out.prntln("进行安全检查");return returnvalue;}}
- spring小结一
- spring小结(一)
- Spring 小结(一)
- spring-mvc(一)spring-mvc原理小结
- Spring小结
- Spring小结
- Spring 小结
- spring小结
- Spring小结
- Spring小结
- spring 小结
- Spring小结
- spring小结
- Spring小结
- Spring 小结
- spring小结
- Spring小结
- 小结一
- 转载的优酷视频不能自动播放和全屏的解决方法
- 《Linux命令行与shell脚本编程大全》 第十章 学习笔记
- Ubuntu12.10 icescrum 设置
- 订票
- poj2864
- spring小结一
- 15-数字、字符串和集合
- java定义二维数组的几种写法
- 一套较完整的技术框架
- puppet kick forbidden finished with exit code 2
- 已知二叉树的节点数,求树的深度
- 散记-const
- java中的全局变量
- 零长度数组