spring入门(二)AOP

接着上面的内容。

        今天主要学习的是AOP

        一、什么是AOP?

            Aspect-Oriented Programming, 面向切面编程。

            举个例子,我们去市场买菜,为了防止商家卖的菜有农药残留,我们需要随身带一个校测器,每买一个菜我们都需要自己手动去检查。当我们使用了AOP之后,我们只需要去买菜,AOP自动帮我们完成了检测是否有农药的残留。

            到我们的Javabean中,我们要操作一个方法,比喻添加用户,在添加用户之前我们需要校验权限,在添加用户后我们需要做一个事后日志记录,如果每个方法我们都需要这么做的话,将会是一个很大的工程,当某天我们不需要这个这个权限的时候,又需要一个个删除,想想就快崩溃了。那么我们有没有将权限校验和时候日志记录抽取出来。AOP就给我们提供了这样的方法。

        二、使用AOP的好处

        1、日志记录的代码和真正的业务逻辑代码进行分离 

        2、通用的系统功能(日志记录、权限校验)进行了高度的模块化 

        3、业务逻辑的功能变的更简洁,仅仅包含业务逻辑的代码 

        4、AOP可以将系统功能(日志记录)与业务逻辑功能搅和到一起执行

        三、AOP的两种底层实现方式

        1、动态代理

            1.1    什么是代理

                代理设计模式的原理: 使用一个代理对象将原始对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理对象. 代理对象决定是否以及何时将方法调用转到原始对象上。

            1.2 静态代理

@Override
    public boolean update(User user) {
        System.out.println("执行权限校验,日志记录.......");
        return userService.update(user);
    }

            为每一个类手动添加代理方式,如果类很多,将会是一个很庞大的工程,因此我们采用动态代理的方式

        1.3 动态代理的好处

            我们可以在系统运行时,动态生成一个持有原始对象,并实现代理接口的Proxy,同时 “植入”我们的通用逻辑(日志、权限等)。 

        动态代理可以实现静态代理相同的功能,唯一的区别这些Proxy的创建都是自动的并且在系统运行时生成的。这样就不需要对每一个原始对象来创建一个代理了。 

        接下来我们看动态代理的两种实现方式:JDK动态代理和CGLIB动态代理

        2、JDK动态代理

        2.1创建maven工程,导包

<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.8</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

           2.2 定义接口和实现类

public interface UserService {
	
	public String getbyid();
	public void add();
	public void delete();
	public void update();
	public void batch();
}
public class UserServiceImpl implements UserService {

	@Override
	public void add() {
		System.out.println("执行具体的业务逻辑:add......");

	}

	@Override
	public String getbyid() {
		System.out.println("执行具体的业务逻辑:getbyid......");
		return null;
	}

	@Override
	public void delete() {
		System.out.println("执行具体的业务逻辑:delete......");

	}

	@Override
	public void update() {
		System.out.println("执行具体的业务逻辑:update......");

	}

	@Override
	public void batch() {
		System.out.println("执行具体的业务逻辑:batch......");

	}

}

        2.3、定义逻辑增强(切面类:封装增强逻辑)

public class SecurityAspect {
	//校验逻辑
	public void check(){
		System.out.println("校验权限............................");
		
	}
}

        2.4、对原始对象创建他的代理对象

//创建代理对象
public class ProxyFactory implements InvocationHandler {

		// 目标对象
		private Object msg;
	
		public ProxyFactory(Object msg) {
			super();
			this.msg = msg;
		}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 获取切面类并执行切面增强
		SecurityAspect securityAspect = new SecurityAspect();
		securityAspect.check();
		// 执行目标对象方法
		Object invoke = method.invoke(msg, args);
		return invoke;
	}

	// 创建代理对象
	public Object getproxy() {

		return Proxy.newProxyInstance(msg.getClass().getClassLoader(),
				msg.getClass().getInterfaces(), this);
	}

}

            2.5、创建测试类

@Test
	public void testName2() throws Exception {
		UserService userService = new UserServiceImpl();
		UserService user = (UserService) new ProxyFactory(userService).getproxy();
		user.add();
	}

        2.6存在的问题

                使用内置的Proxy(JDK动态代理)实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理。

        3、CGLIB动态代理

            cglib继承被代理的类(UserServiceImpl),重写方法,织入通知,动态生成字节码并运行,因为是继承所以final类是没有办法动态代理的。

            3.1定义我们的目标类(不需要实现接口)

public class UserCglib {
	public void show(String string){
		System.out.println("目标类方法"+string);
	}
}

        3.2、定义我们的切面

public class UserAspct {
	public void writelog(){
		System.out.println("我是切面控制对象的");
		
	}
}

        3.3、定义动态代理

public class CglibPorxyFactory   implements MethodInterceptor {

	//目标类
	private  Object msg;
	//逻辑增强
	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
		//获取拦截类,执行拦截方法
		UserAspct userAspct = new UserAspct();
		userAspct.writelog();
		//获取目标类,执行目标方法
		Object invokeSuper = proxy.invokeSuper(o, objects);
		return invokeSuper;
	}
	//获取代理对象
	public Object getproxy(Object msg) {
		this.msg=msg;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(msg.getClass());
		enhancer.setCallback(this);
		Object create = enhancer.create();
		return create;
	}
}

        3.4、测试类

@Test
	public void testName() throws Exception {
			UserCglib getproxy = (UserCglib) new CglibPorxyFactory().getproxy(new UserCglib());
			getproxy.show("===================>小泽");
		
	}

            四、AOP 中的专业术语

                切面(aspect):横切逻辑被模块化的特殊对象。即它是一个类 :如LogAspect 

                通知(advice):切面中必须完成的工作。即它是类中的一个方法:如writeLog() 

                目标类(target):被通知增强的对象 

                代理类(proxy):向目标类应用通知增强之后产生的对象 

                切入点(pointcut):切面中通知执行的“地点”的定义 

                连接点(JoinPoint): 与切入点匹配的执行点:如目标类中的所有方法getUserId()

            

            五、AOP基于xml配置方式实现

                1、Spring基于xml开发AOP

                1.1创建接口及实现类

public interface UserService {
	
	public String getbyid();
	public void add();
	public String delete();
	public void update();
	public void batch();
}
public class UserServiceImpl implements UserService {

	@Override
	public void add() {
		System.out.println("执行具体的业务逻辑:add......");

	}

	@Override
	public String getbyid() {
		System.out.println("执行具体的业务逻辑:getbyid......");
//		System.out.println(1/0);
		return null;
	}

	@Override
	public String delete() {
		System.out.println("执行具体的业务逻辑:delete......");
		return "大数据";
		
//		System.out.println(1/0);
	}

	@Override
	public void update() {
		System.out.println("执行具体的业务逻辑:update......");
//		System.out.println(1/0);
	}

	@Override
	public void batch() {
		System.out.println("执行具体的业务逻辑:batch......");
		
	}

}

            1.2、定义切面类

public class XmlAspect {
	
	public void beforAspect(JoinPoint jp  ){
		System.out.println(jp.getSignature().getName());
		System.out.println("我是前置,我要先执行.........................");
	}
	public void afterAspect(){
		System.out.println("我是后置办法,我要后执行.........................");
	}
	public void afterReturningAspect(JoinPoint jp,Object obj){
		System.out.println(obj);
		System.out.println("我是返回办法,不管对错我都要执行........................");
	}
	public void exceptionAspect(Exception ex){
		System.out.println(ex);
		System.out.println("我是报错,有错我就执行.........................");
	}
	public Object aroundAspect( ProceedingJoinPoint jp ) throws Throwable{
		System.out.println("我是环绕通知前.........................");
		Object proceed = jp.proceed();
		
		System.out.println("我是环绕通知后.........................");
		return proceed;
	}

}

        1.3  在Spring容器中配置目标类、切面类、配置核心文件

<?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:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">


	<!-- 注册目标及切面对象 -->
	<bean id="userserv" class="cn.itcast.dao.xml.UserServiceImpl"></bean>

	<bean id="xmlaspect" class="cn.itcast.dao.xml.XmlAspect"></bean>
	<!-- 配置spring核心配置文件:配置切入点、通知、切面 -->
	<aop:config>
		<!-- 切入点配置 -->
		<aop:pointcut expression="execution(* *.add*(..))" id="atter1" />
		<aop:pointcut expression="execution(* *.getbyid*(..))"
			id="atter2" />
		<aop:pointcut expression="execution(* *.delete*(..))" id="atter3"   />
		<aop:pointcut expression="execution(* *.update*(..))" id="atter4" />
		<aop:pointcut expression="execution(* *.batch*(..))" id="atter5" />

		<!-- 切面配置 -->
		<aop:aspect ref="xmlaspect">
			<!-- 前置通知配置 -->
			<aop:before method="beforAspect" pointcut-ref="atter1" />
			<!-- 后置通知 -->
			<aop:after method="afterAspect" pointcut-ref="atter2" />
			<!-- 返回通知 -->
			<aop:after-returning method="afterReturningAspect"
				pointcut-ref="atter3"  returning="obj" />
			<!-- 报错通知 -->
			<aop:after-throwing method="exceptionAspect"
				pointcut-ref="atter4"  throwing="ex" />
			<!-- 环绕通知 -->
			<aop:around method="aroundAspect" pointcut-ref="atter5" />
		</aop:aspect>
	</aop:config>


</beans>

        1.4 测试类

    

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-aop-xml.xml")
public class Xmltest {

	@Autowired//在spring容器中获取目标代理对象
	private UserService service;

	@Test
	public void testName() throws Exception {
		service.add();
//		service.getbyid();
//		service.delete();
//		service.update();
//		service.batch();

	}

}

                六、AOP基于注解方式的实现

                1、开启spring注解扫描及开启aop注解的自动代理

<?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:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
		
<!-- 		扫描注解 -->
		<context:component-scan base-package="cn.itcast.spring.annotation"></context:component-scan>
<!-- 		开启自动代理 -->
		<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

                2、定义接口和实现类

    

public interface UserService {
	
	public String getbyid();
	public void add();
	public String delete();
	public void update();
	public void batch();
}
@Service//将这个类放在Spring容器中
public class UserServiceImpl implements UserService {

	@Override
	public void add() {
		System.out.println("执行具体的业务逻辑:add......");

	}

	@Override
	public String getbyid() {
		System.out.println("执行具体的业务逻辑:getbyid......");
//		System.out.println(1/0);
		return null;
	}

	@Override
	public String delete() {
		System.out.println("执行具体的业务逻辑:delete......");
//		System.out.println(1/0);
		return "大数据";
	}

	@Override
	public void update() {
		System.out.println("执行具体的业务逻辑:update......");
//		System.out.println(1/0);
	}

	@Override
	public void batch() {
		System.out.println("执行具体的业务逻辑:batch......");
		
	}

}

                3、定义切面类

@Component
@Aspect
public class AspectaAnnotation {
	
	@Before(value = "execution(* *.add*(..))")
	public void beforAspect(JoinPoint jp  ){
		System.out.println(jp.getSignature().getName());
		System.out.println("我是前置,我要先执行.........................");
	}
	
	@After(value = "execution(* *.getbyid*(..))")
	public void afterAspect(){
		System.out.println("我是后置办法,不管对错我都要执行执行.........................");
	}
	
	
	
	
	@AfterReturning(value="execution(* *.delete*(..))",returning="obj"   )
	public void afterReturningAspect(JoinPoint jp,Object obj){
		System.out.println(obj);
		System.out.println("我是返回办法,........................");
	}
	
	
	@AfterThrowing(value="execution(* *.update*(..))",throwing="ex")
	public void exceptionAspect(Exception ex){
		System.out.println(ex);
		System.out.println("我是报错,有错我就执行.........................");
	}
	
	
	
	@Around(value = "execution(* *.batch*(..))")
	public Object aroundAspect( ProceedingJoinPoint jp ) throws Throwable{
		System.out.println("我是环绕通知前.........................");
		Object proceed = jp.proceed();
		
		System.out.println("我是环绕通知后.........................");
		return proceed;
	}
	
	
}

                4、测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-aop-annotation.xml")
public class Annotationtest {
	@Autowired
	private UserService service;
	@Test
	public void testName() throws Exception {
//		service.add();
//	service.getbyid();
//	service.delete();
//		service.update();
		service.batch();
	}

}


            



猜你喜欢

转载自blog.csdn.net/qq595662096/article/details/80191183