Spring

spring基础

spring IOC (控制反转)

搭建spring环境

下载spring框架:http://maven.springframework.org/release/org/springframework/spring/

我们在解压后的压缩包里面找到5个jar包:

spring-aop.jar 开发AOP特性时需要的JAR
spring-beans.jar 处理Bean的jar
spring-context.jar 处理spring上下文的jar
spring-core.jar spring核心jar
spring-expression.jar spring表达式

三方提供的日志jar: commons-logging.jar 日志

  1. 编写配置文件

    建议下载sts工具:https://spring.io/tools/sts/

    或者使用开发工具IDEA

  2. 开发spring程序(IOC)

    新建一个Java项目,在src目录下新建一个applicationContext.xml文件

    在上述文件下配置自己的bean

    <bean id="student" class="完整的包名">
    
    </bean>
    

    spring帮助我们new对象

    ApplicationContext conext = new                   ClassPathXmlApplicationContext("applicationContext.xml") ;
    		//执行从springIOC容器中获取一个 id为student的对象
    		Student student = (Student)conext.getBean("student") ;
    
    <bean id="student" class="org.syy.entity.Student">
    	<property name="stuNo" value="2"></property>
    	<property name="stuName" value="ls"></property>
    	<property name="stuAge" value="20"></property>
    </bean>
    

    ​ 使用student需要有student实体类,用property赋值需要在三个属性中需要有set方法

    */

    ​ Student student = (Student)conext.getBean(“student”) ;

    ​ System.out.println(student);

  3. 总结

    IOC(控制反转)也可以称之为DI(依赖注入):
    控制反转:将 创建对象、属性值 的方式 进行了翻转,从new、setXxx() 翻转为了 从springIOC容器 getBean()
    依赖注入:将属性值 注入给了属性,将属性 注入给了bean,将bean注入给了ioc容器;

    总结:ioc/di ,无论要什么对象,都可以直接去springioc容器中获取,而不需要自己操作(new\setXxx())

    因此之后的ioc分为2步:1. 先给springioc中存放对象并赋值 2.拿

    在ioc中定义bean的前提:该bean的类 必须提供了 无参构造

    ​ IOC容器赋值

    1. 基本类型(8个基本类型+String) 直接通过value 赋值
    2. 对象类型,ref=“需要引用的id值”,因此实现了 对象与对象之间的依赖关系
    • 依赖注入方式:

      • 1.set注入:通过setXxx()赋值

        赋值,默认使用的是 set方法();
        依赖注入底层是通过反射实现的。
        <property…>

      • 2.构造器注入:通过构造方法赋值

         <constructor-arg 
              value="ls" 
              type="String" 
              index="0" 
              name="name">
           </constructor-arg>
         
        

        需要注意:如果 的顺序 与构造方法参数的顺序不一致,则需要通过type或者index或name指定。

      • 3.p命名空间注入
        引入p命名空间
        xmlns:p=“http://www.springframework.org/schema/p”

        <bean id="course" class="org.lanqiao.entity.Course" p:courseHour="300" p:courseName="hadoop" p:teacher-ref="teacher">
        
      给对象类型赋值null :
      		<property name="name" >  
      				<null/>       -->注意 没有<value>
      		</property>
      赋空值 ""  
      		<property name="name" >  
      				<value></value>  
      		</property>
      
      

使用注解定义bean(推荐)

通过注解的形式 将bean以及相应的属性值 放入ioc容器。

需要配置扫描器:

<!-- 配置扫描器 -->
<context:component-scan base-package="org.syy.dao.impl,org.syy.service.impl,org.syy.aop">
</context:component-scan>

Spring在启动的时候,会根据base-package在 该包中扫描所有类,查找这些类是否有注解 @Component(“studentDao”),如果有,则将该类 加入spring Ioc容器。

@Component细化:(可分为三层)

dao层注解:@Repository
service层注解:@Service
控制器层注解:@Controller

spring AOP(面向方面编程)

把一个普通的类变成有特定功能的类

类 -> “通知” :

1.实现接口
  • 前置通知

    • 引入jar包 aopliance.jar + aspectjweaver.jar

    • 编写前置通知类:logBefore 需要继承前置通知的一个接口

      package org.syy.aop;
      import java.lang.reflect.Method;
      import org.springframework.aop.MethodBeforeAdvice;
      public class LogBefore implements MethodBeforeAdvice{
      	@Override
      	public void before(Method method, Object[] args, Object target) throws Throwable {
      		System.out.println("前置通知:目标对象:"+target+",调用的方法名:"+method.getName()+",方法的参数个数:"+args.length);
      		
      	}
      }
      

      然后在applicationContext.xml配置

      <!-- “前置通知”类 -->
      	<!-- =========连接线的一方========= -->
          <!--将通知纳入springIOC容器-->
      	<bean id="logBefore" class="org.syy.aop.LogBefore"></bean>
      
      	<!--addStudent() 和  通知 进行关联 -->
      	<aop:config>
      	<!-- 配置切入点  (在哪里执行通知 ) -->
      	<!-- =========连接线的另一方========= -->
      		<aop:pointcut expression="execution(public void org.syy.service.impl.StudentServiceImpl.deleteStudentByNo(int))  or execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))" id="pointcut"/>
      		<!-- advisor:相当于 链接切入点 和切面的线  -->		
      		<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/>
      	</aop:config>
      

      然后我们可以写测试类

      	public static void testAop() {
      		ApplicationContext context = new        ClassPathXmlApplicationContext("applicationContext.xml") ;
      		IStudentService studentService =  (IStudentService)context.getBean("studentService") ;
      		Student student = new Student();
      		studentService.addStudent(student);
      	}
      
  • 后置通知

    package org.syy.aop;
    
    import java.lang.reflect.Method;
    
    import org.springframework.aop.AfterReturningAdvice;
    
    public class LogAfter implements AfterReturningAdvice{
    
    	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    		System.out.println("后置通知:目标对象:"+target+",调用的方法名:"+method.getName()+",方法的参数个数:"+args.length+",方法的返回值:"+returnValue);
    	}
    
    }
    

    在applicationContext.xml中配置

    <!-- 后置通知 -->
    	<!-- 将通知纳入springIOC容器 -->
    	<bean id="logAfter" class="org.syy.aop.LogAfter"></bean>
    	
    	<aop:config>
    		<!-- 切入点(连接线的一端) 业务类的方法 -->
    		<aop:pointcut expression="execution(public void org.syy.service.impl.StudentServiceImpl.deleteStudentByNo(int))  or execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))" id="pointcut2"/>
    		<!-- 连接线的另一端:通知类 -->
    		<aop:advisor advice-ref="logAfter" pointcut-ref="pointcut2"/>
    	
    	</aop:config>
    
  • 异常通知

    根据异常通知接口的定义可以发现,异常通知的实现类 必须编写以下方法:

    	public void afterThrowing([Method, args, target], ThrowableSubclass):
    
    	a.public void afterThrowing(Method, args, target, ThrowableSubclass)
    	b.public void afterThrowing( ThrowableSubclass)
    
    
    package org.syy.aop;
    import java.lang.reflect.Method;
    import org.springframework.aop.ThrowsAdvice;
    
    public class LogException implements ThrowsAdvice{
    	//必须重写该方法
    	public void afterThrowing(Method method,Object[] args,Object target, Throwable ex) 
    	{
    		System.out.println("异常通知:目标对象:"+target+",方法名:"+method.getName()+",方法的参数个数:"+args.length+",异常类型:"+ex.getMessage());
    	}
    }
    

    在applicationContext.xml 中配置

    <bean id="logException" class="org.syy.aop.LogException"></bean>
    	
    		<aop:config>
    		<!-- 切入点(连接线的一端) 业务类的方法 -->
    		<aop:pointcut expression="execution(public void org.syy.service.impl.StudentServiceImpl.deleteStudentByNo(int))  or execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))" id="pointcut3"/>
    		<!-- 连接线的另一端:通知类 -->
    		<aop:advisor advice-ref="logException" pointcut-ref="pointcut3"/>
    	
    	</aop:config>
    
    
  • 环绕通知

    在目标方法的前后、异常发生时、最终等各个地方都可以 进行的通知,最强大的一个通知;
    可以获取目标方法的 全部控制权(目标方法是否执行、执行之前、执行之后、参数、返回值等)

    在使用环绕通知时,目标方法的一切信息 都可以通过invocation参数获取到环绕通知 底层是通过拦截器实现的。

    package org.syy.aop;
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class LogAround implements MethodInterceptor{	
    	public Object invoke(MethodInvocation invocation) throws Throwable {
    		
    		Object result = null;
    		try {			
    		System.out.println("用环绕通知实现的[前置通知]...");
    		/*该语句之前为前置通知*/
    		result = invocation.proceed();//控制目标方法执行 addStudent()
    		System.out.println("用环绕通知实现的[后置通知]...:");
    //		System.out.println("-----------------目标对象target:"+invocation.getThis()+",调用的方法名:"+invocation.getMethod().getName()+",方法的参数个数:"+invocation.getArguments().length+",返回值:"+result);
    		/*该语句之后为后置通知*/
    		} catch (Exception e) {
    			//异常通知
    			System.out.println("用环绕通知实现的[异常通知]...");
    		}	
    		return result;//目标方法的返回值
    	}
    }
    

    在applicationContext.xml 中配置

    <!-- 环绕通知 -->
    	<bean id="logAround" class="org.syy.aop.LogAround" ></bean>
    	<aop:config>
    		<aop:pointcut expression="execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))" id="pointcut4"/>
    		<aop:advisor advice-ref="logAround" pointcut-ref="pointcut4" />
    	</aop:config>
    
    
2.注解实现通知
  • 首先开启对aop注解的支持
<!-- 开启注解对AOP的支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Aspect  //声明该类 是一个 通知
public class LogBeforeAnnotation  {
    
}

通过注解形式 实现的aop,如果想获取 目标对象的一些参数,则需要使用一个对象:JointPoint

注解形式的返回值:

a.声明返回值 的参数名:
	@AfterReturning( pointcut= "execution(public * addStudent(..))" ,returning="returningValue" ) 
	public void myAfter(JoinPoint jp,Object returningValue) {//returningValue是返回值,但需要告诉spring
		System.out.println("返回值:"+returningValue );
//注解形式实现aop时,通知的方法的参数不能多、少

package org.syy.aop;

import org.aspectj.lang.JoinPoint;
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;
import org.springframework.stereotype.Component;

@Component("LogAnnotation")
@Aspect//此类是一个通知
public class LogAspectAnnotation {
	
	//前置通知
	@Before(value = "execution(public void org.syy.service.impl.StudentServiceImpl.deleteStudentByNo(int))  or execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))")//定义切点
	public void myBefor(JoinPoint jp) {
		System.out.println("《注解形式-前置通知》:目标对象:"+jp.getTarget()+",方法名:"+jp.getSignature().getName() +",参数列表:"+ jp.getArgs().length);
	}
    
	/*后置通知*/
	@AfterReturning(pointcut  = "execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))",returning = "returningValue")
	public void myAfter(JoinPoint jp,Object returningValue) {
		System.out.println("《注解形式-后置通知》:目标对象:"+jp.getTarget()+",方法名:"+jp.getSignature().getName() +",参数列表:"+  jp.getArgs().length+",返回值:"+returningValue);
	}	
    
	//环绕通知
	@Around("execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))")
	public void myAround(ProceedingJoinPoint jp){
		//方法执行之前:前置通知
		System.out.println("《【环绕】方法之前:前置通知");
		try {
			//方法执行时
			jp.proceed() ;//执行方法
			//方法执行之后:后置通知
			System.out.println("《【环绕】方法之前之后:后置通知");
		} catch (Throwable e) {
			//异常通知
			System.out.println("《【环绕】发生异常时:异常通知");
		} finally {
			//最终通知
			System.out.println("《【环绕】最终通知");
		}
	}
    
	//异常通知
	@AfterThrowing(pointcut = "execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))",throwing = "e")
	public void myException(JoinPoint pj, NullPointerException e) 
	{
		System.out.println("《注解形式-异常通知》----e:"+e.getMessage());
	}
	
	//最终通知
	@After("execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))")
	public void myFinally()
	{
		System.out.println("注解形式-最终通知-----");
	}
}

3.基于Schema配置
  • 接口方式通知:public class LogAfter implements AfterReturningAdvice
    Schema方式通知:
    a.编写一个普通类 public class LogAfter {}
    b.将该类 通过配置,转为一个“通知”
  • 如果要获取目标对象信息:
    注解、schema:JoinPoint
    接口:Method method, Object[] args, Object target

编写配置类

package org.syy.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class LogSchema {
	
	//后置通知方法  :JoinPoint适用于注解
	public void afterReturning(JoinPoint jp,Object returnValue) throws Throwable {
		System.out.println("schema-后置通知:目标对象:"+jp.getThis()+",调用的方法名:"+jp.getSignature().getName()+",方法的参数个数:"+jp.getArgs().length+",方法的返回值:"+returnValue);
	}

	public void before() {
		System.out.println("schema-前置通知...");
	}
	
	public void whenException(JoinPoint jp,NullPointerException e) {
		System.out.println("schema-异常:" +e.getMessage());
	}
	//注意:环绕通知 会返回目标方法的返回值,因此返回值为Object
	public Object around(ProceedingJoinPoint jp)    {
		System.out.println("schema-环绕通知:前置通知");
		Object result = null ; 
		try {
			 result = jp.proceed() ;//执行方法
			 System.out.println("schema-"+jp.getSignature().getName()+","+result);
			System.out.println("schema-环绕通知:后置通知");
		}catch(Throwable e) {
			System.out.println("schema-环绕通知:异常通知");
		}
		return result ;
	}
}

在applicationContext.xml 中配置

<bean id="logSchema" class="org.syy.aop.LogSchema"></bean>
	<aop:config>
		<aop:pointcut expression="execution(public * org.syy.service.impl.StudentServiceImpl.addStudent(..))" id="pcShema"/>
		
		<aop:aspect ref="logSchema">
			
			<aop:before method="before" pointcut-ref="pcShema"/>
			
			<aop:after-returning method="afterReturning" returning="returnValue" pointcut-ref="pcShema"/>

			<aop:after-throwing method="whenException" pointcut-ref="pcShema" throwing="e"/>
			<!-- 环绕 -->
			<aop:around method="around" pointcut-ref="pcShema"/>
		</aop:aspect>
	
	</aop:config>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值