Spring中的代理
概念:代理即在访问真正的对象之前和之后所做的业务处理的对象
以事务的操作为例讲解:
静态代理
代理对象和真实的对象需要实现同一个接口
目标对象类
public class UserDaoImpl implements IUserDao {
@Override
public int saveUser() {
//System.out.println("--开启事务--");
System.out.println("--添加用户--");
//System.out.println("--关闭事务--");
return 0;
}
@Override
public int delUser() {
//System.out.println("--开启事务--");
System.out.println("--删除用户--");
//System.out.println("--关闭事务--");
return 0;
}
}
代理对象类
public class ProxyUserDaoImpl implements IUserDao{
//UserDaoImpl userDao = new UserDaoImpl();
IUserDao userDao;
public ProxyUserDaoImpl(IUserDao userDao){
this.userDao = userDao;
}
@Override
public int saveUser() {
System.out.println("--开启事务--");
userDao.saveUser();
System.out.println("--关闭事务--");
return 0;
}
@Override
public int delUser() {
System.out.println("--开启事务--");
userDao.delUser();
System.out.println("--关闭事务--");
return 0;
}
}
测试类
@Test
public void test(){
IUserDao userDao = new ProxyUserDaoImpl(new UserDaoImpl2());
userDao.delUser();
userDao.saveUser();
}
动态代理(JDK代理)
在程序运行期间,动态的创建代理对象
//目标对象类与上述相同
//测试方法
@Test
public void test2(){
//真实对象
IUserDao userDao = new UserDaoImpl();
//创建代理对象
//ClassLoader 加载真实对象的class文件
//Class<?>[] 真实对象所实现的所有接口
IUserDao proxy = (IUserDao) Proxy.newProxyInstance(
userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
//代理对象要做的事情
new InvocationHandler(){
//proxy 代理对象
//method 目标对象中的方法的描述方法
//args 目标对象中方法的参数
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("开启事务");
//每个要代理的方法都会执行
//通过反射机制,找到要执行的dao里面的方法
Object obj = method.invoke(userDao, args);
System.out.println("关闭事务");
return obj;
}
}
);
proxy.delUser();
proxy.saveUser();
}
问题:必须要有接口
cglib代理(字节码增强)
导入jar,只需要提供要代理的类即可
jar:asm.jar cglib.jar或者使用Spring-core.jar(其中包含的有)
目标对象类
public class UserDaoImpl2 {
public int saveUser() {
//System.out.println("--开启事务--");
System.out.println("--添加用户2--");
//System.out.println("--关闭事务--");
return 0;
}
public int delUser() {
//System.out.println("--开启事务--");
System.out.println("--删除用户2--");
//System.out.println("--关闭事务--");
return 0;
}
}
测试类
@Test
public void tests3(){
//创建目标对象
UserDaoImpl2 userDaoImpl2 = new UserDaoImpl2();
//创建Enhancer设置相关属性及创建代理对象--cglib
Enhancer enhancer = new Enhancer();
//指定要代理的对象
enhancer.setSuperclass(UserDaoImpl2.class);
//设置回调函数处理代理方法
enhancer.setCallback(new MethodInterceptor(){
public Object intercept(Object proxy,Method method,Object[] args,MethodProxy methodProxy){
System.out.println("开启事务");
Object obj = method.invoke(userDaoImpl2,args);
//methodProxy.invokeSuper(proxy,args);
System.out.println("关闭事务");
return obj;
}
});
//创建代理对象
UserDaoImpl2 proxy = (UserDaoImpl2)enhancer.create();
proxy.delUser();
proxy.saveUser();
}
Spring中的AOP
1、面向切面编程:采用横向抽取的方式,在程序运行的过程中,动态的向目标对象中织入要增强的代码。底层采用动态代理方式(JDK代理和cglib代理)
2、应用场景
事务管理、日志、性能监控等…
3、术语解释
target:目标对象
advice:通知(增强代码)
joinpoint:连接点,可能要添加增强代码的方法
pointcut:切入点,要添加增强代码的方法
weaving:织入,将增强代码添加到切入点的过程
aspect:切面,切入点和增强代码之间形成的虚拟的面
4、案例–给删除方法添加事务管理,使用aspectj框架而非Spring aop
步骤:
a)创建项目,导入jar。
4+1 core context bean spel jcl
spring-aop.jar 基于aspectj实现的
spring-aspects.jar aspectj的规则
aspectjweaver.jar 织入的技术
aopalliance.jar 设置通知的规则
b)创建目标类和通知类
public class UserServiceImpl implements UserService{
@Override
public int saveUser() {
userDao.saveUser();
return 0;
}
@Override
public int delUser() {
userDao.delUser();
return 0;
}
}
public class MyAdvice{
//JoinPoint用于获取目标对象中的相关信息
public void before(JoinPoint joinPoint){
System.out.println("添加事务");
}
public void after(){
System.out.println("关闭事务");
}
public void afterReturning(){
System.out.println("后置通知");
}
public void afterThrowing(){
System.out.println("异常通知");
}
//环绕通知,必须手动调用目标对象的方法
public void around(ProceedingJoinPoint joinPoint){
try{
System.out.println("前置");
joinPoint.proceed();
System.out.println("返回");
}catch(){
System.out.println("异常");
}finally{
System.out.println("后置通知");
}
}
}
<!--创建目标对象-->
<bean id="userService" class=""></bean>
<!--创建增强类对象-->
<bean id="myAdvice" class=""></bean>
<!--将通知织入到目标对象上
aop:config属性
proxy-target-class="true" true代表强制使用cglib
-->
<aop:config>
<!--切入点:配置要向什么地方添加增强代码
expression:execution(返回值类型 包名 类名 方法名(参数,...))
* service..*(..)
-->
<aop:pointcut expression="execution(* service..*(..))" id="myPointcut"/>
<!--切面:添加什么,如何添加-->
<aop:aspect ref="myAdvice">
<!--前置通知-->
<!--<aop:before method="before" pointcut-ref="myPointcut"/>-->
<!--后置通知-->
<!--<aop:after method="after" pointcut-ref="myPointcut"/>-->
<!--返回通知-->
<!--<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>-->
<!--异常通知-->
<!--<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>-->
<!--环绕通知-->
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
//测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class AopTest{
@Autowired
UserService userService;
@Test
public void test(){
userService.saveUser();
userService.delUser();
}
}