记录学习的点滴(Spring控制反转、面向切面编程)

Spring控制反转(IoC)
依赖注入(DI)是控制反转(IoC)的另外一种叫法。在Spring之前,类A依赖类B就需要在类A里手动new类B,这样类A才可以使用类B。使用Spring之后,在Spring容器初始化时就通过xml配置文件把类B初始化好,通过类B的setter方法注入给类A,对类A来讲,控制权主动变被动。从而提高代码的灵活性和可维护性。
(*比较言简意赅的解释:对成员变量的赋值的控制权从代码中反转到配置文件中)
Spring面向切面编程(AOP)
①面向切面编程(JDK的动态代理)的四种实现方式:
1、经典的基于代理的AOP
配置ProxyFactoryBean,显示的设置target、advice等
Travelling.java
public interface Travelling {
	
	void travel();
	
}
Our.java
public class Our implements Travelling {

	@Override
	public void travel() {
		System.out.println("第二步,旅行。");
	}

}
TravelHelper.java
public class TravelHelper implements MethodBeforeAdvice, AfterReturningAdvice {

	@Override
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("第三步,回去。");
	}

	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("第一步,出发。");
	}

}
配置文件
applicationContextTravelAOP.xml
	<bean id="our" class="com.test.spring.aop.Our" />
	
	<bean id="travelHelper" class="com.test.spring.aop.TravelHelper" />
	
 	<bean id="travelPointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
		<property name="pattern" value=".*travel" />
	</bean>
	
	<bean id="travelHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="advice" ref="travelHelper" />
		<property name="pointcut" ref="travelPointCut" />
	</bean>
	
	<bean id="ourProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="our" />
		<property name="interceptorNames">
			<list>
				<value>travelHelperAdvisor</value>
			</list>
		</property>
		<property name="proxyInterfaces" value="com.test.spring.aop.Travelling" />
	</bean>
测试类
TravelAOPTest.java
public class TravelAOPTest {
	private static ClassPathXmlApplicationContext ctx;

	public static void main(String[] args) {
		ctx = new ClassPathXmlApplicationContext("classpath:applicationContextTravelAOP.xml");
		Travelling travelling = (Travelling)ctx.getBean("ourProxy");
		travelling.travel();
	}

}
运行结果

2、配置AutoProxyCreator,这种方式下,还是和1一样使用定义的bean,但是从容器中获得的其实已经是代理对象
Spring提供自动代理的功能,能让切点和通知自动进行匹配。
配置文件
 <bean id="travelAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  <property name="advice" ref="travelHelper"></property>
  <property name="pattern" value=".*travel"></property>
 </bean>
 <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
测试类
public class TravelAOPTest {
 private static ClassPathXmlApplicationContext ctx;
 public static void main(String[] args) {
  ctx = new ClassPathXmlApplicationContext("classpath:applicationContextTravelAOP.xml");
  Travelling travelling = (Travelling)ctx.getBean("our");
  travelling.travel();
 }
}
运行结果和1的运行结果一致。
3、通过<aop: aspectj-autoproxy>来配置,使用注解方式
TravelHelper.java
@Aspect
public class TravelHelper {
 public TravelHelper() {}
 
 @Pointcut("execution(* *.travel())")
 public void travelPointCut(){
 }
 @Before("travelPointCut()")
 public void beforeTravel(){
  System.out.println("第一步,出发。");
 }
 
 @AfterReturning("travelPointCut()")
 public void afterTravel(){
  System.out.println("第三步,回去。");
 }
}
配置文件
<aop:aspectj-autoproxy />
以下内容必须
2aspectjweaver.jar要引入,同时要注意和jdk的版本要一致。
4、通过<aop:config>来配置纯粹的POJO切面
applicationContextTravelAOP.xml
 <aop:config>
  <aop:aspect ref="travelHelper">
   <aop:before method="beforeTravel" pointcut="execution(* *.travel(..))"/>
   <aop:after-returning method="afterTravel" pointcut="execution(* *.travel(..))"/>
  </aop:aspect>
 </aop:config>
TravelHelper.java
public class TravelHelper {
 public TravelHelper() {}
 
 public void travelPointCut(){
 }
 public void beforeTravel(){
  System.out.println("第一步,出发。");
 }
 public void afterTravel(){
  System.out.println("第三步,回去。");
 }
}
②面向切面编程(CGLIB)的实现方式:
JDK的动态代理必须是基于接口的,但是实际开发中,好多类并不是基于接口编程的。这个时候便可以使用基于类实现动态代理的CGLib。
Travelling.java(目标类)
package com.test.cglib.aop;

public class Travelling {
	
	void travel(){
		System.out.println("第二步:旅行。");
	}
	
}
TravellingHelper.java(切面类)
package com.test.cglib.aop;

import java.lang.reflect.Method;

public class TravellingHelper {

	public void before(Method method) {
		System.out.println("第一步:出发。");
	}

	public void after(Method method) {
		System.out.println("第三步:回来。");
	}

}

CGLibProxy.java
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 target;
	
	// 切面操作方法
	private Object pointCut;
	
	public Object bind(Object targetObj, Object pointCut) {
		this.target = targetObj;
		this.pointCut = pointCut;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(this.target.getClass());
		// 回调方法
		enhancer.setCallback(this);
		// 创建代理对象
		return enhancer.create();
	}

	@Override
	public Object intercept(Object target, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		Object result;
		// 反射得到操作者的实例
		Class<? extends Object> clazz = this.pointCut.getClass();
		// 反射得到操作者的before方法
		Method before = clazz.getDeclaredMethod("before", new Class[]{ Method.class });
		// 反射执行before方法
		before.invoke(this.pointCut, new Object[]{ method });
		// 执行操作对象的原先方法
		result = proxy.invokeSuper(target, args);
		// 反射得到操作者的after方法
		Method after = clazz.getDeclaredMethod("after", new Class[]{ Method.class });
		// 反射执行after方法
		after.invoke(this.pointCut, new Object[]{ method });
		
		return result;
	}

}
CGLib核心类
1、net.sf.cglib.proxy.Enhancer:主要增强类,通过字节码技术动态创建委托类的子类实例;
2、net.sf.cglib.proxy.MethodInterceptor:常用的方法拦截器接口,需要实现intercept方法,实现具体拦截处理;
public java.lang.Object intercept(java.lang.Object target,
                                  java.lang.reflect.Method method,
                                  java.lang.Object[] args,
                                  MethodProxy proxy)
                           throws java.lang.Throwable
target:动态生成的代理对象
method : 实际调用的方法
args:调用方法入参
proxy:
net.sf.cglib.proxy.MethodProxy:java Method类的代理类,可以实现委托类对象的方法的调用;常用方法:methodProxy.invokeSuper(proxy, args);在拦截方法内可以调用多次
测试类
package com.test.cglib.aop;

import org.junit.Test;

public class CGLibProxyTest {

	@Test
	public void test() {
		Travelling travelling = (Travelling) new CGLibProxy().bind(
				new Travelling(), new TravellingHelper());
		
		travelling.travel();
	}
}
运行结果





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值