大连密封材料 发表于 6 天前

Spring2~~~

注解配置Bean

https://i-blog.csdnimg.cn/direct/a3d55cb648f3489393540b35b41b8f6a.png
https://i-blog.csdnimg.cn/direct/8649685961e3479e8ca4447160e23b1d.png
   Spring的 IOC 容器检查到注解就会天生对象,但这个注解的详细含义不会辨认 
  配置自动扫描的包

    <!--配置容器要扫描的包
    1. component-scan 要对指定包下的类进行扫描, 并创建对象到容器
    2. base-package 指定要扫描的包
    3. 含义是当spring容器创建/初始化时,就会扫描com.hspedu.spring.component包
       下的所有的 有注解 @Controller / @Service / @Respository / @Component类
       将其实例化,生成对象,放入到ioc容器
    -->
    <context:component-scan base-package="com.hspedu.spring.component"/> https://i-blog.csdnimg.cn/direct/61fcb4a101ec4ed696622698f803c1b2.png
Map里的默认id是类名开头小写
com.hspedu.spring.component会扫描comonent及其子包
假如要扫描spring下的包,写成com.hspedu.spring.* 

只扫描包下的哪些类

在xml中加上 resource-pattern="User*.class" 表现只扫描spring.component 和它的子包下的User打头的类,用的比较少
<context:component-scan base-package="com.hspedu.spring.component"
resource-pattern="User*.class" /> 清除包下某种类型的注解(注解方式)

    <!--
      需求:如果我们希望排除某个包/子包下的某种类型的注解,可以通过exclude-filter来指定
      1. context:exclude-filter 指定要排除哪些类
      2. type 指定排除方式 annotation表示按照注解来排除
      3. expression="org.springframework.stereotype.Service" 指定要排除的注解的全路径
    -->

    <context:component-scan base-package="com.hspedu.spring.component">
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan> 指定自动扫描哪些注解类(注解方式)

    <!--
      需求:如果我们希望按照自己的规则,来扫描包/子包下的某些注解, 可以通过 include-filter
      1. use-default-filters="false" 表示不使用默认的过滤机制/扫描机制
      2. context:include-filter 表示要去扫描哪些类
      3. type="annotation" 按照注解方式来扫描/过滤
      4. expression="org.springframework.stereotype.Service" 指定要扫描的注解的全路径
    -->

    <context:component-scan base-package="com.hspedu.spring.component" use-default-filters="false">
       <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
       <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
       <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
使用 value 指定 id 值

        覆盖默认的id值
        注解默认 类名首字母小写 作为id值
https://i-blog.csdnimg.cn/direct/f00c3d059dd840d486c348d8d9e9c62e.png
@Service(value = "sss")
public class Student {
} 自动装配

@AutoWired

https://i-blog.csdnimg.cn/direct/08bd7699425141a6bc25b93bc09d75cd.png
   IOC容器中有多个对象,要举行查找
1、是否有唯一bean
2、根据id查找
根据id查找没找到,报错缘故原由:按id找不到,按类型有多个,类型匹配不上
根据唯一性查找,属性名无所谓,直接按照类型找到
IOC容器中的对象和装配的对象哈希值不肯定一样
    <!--自动扫描的id就是类名首字母小写或者指定value的id值-->
    <context:component-scan
            base-package="com.hspedu.spring.component"/>
    <!--配置两个UserService对象-->
    <bean class="com.hspedu.spring.component.UserService" id="userService200"/>
    <bean class="com.hspedu.spring.component.UserService" id="userService300"/> @Controller
public class UserAction {
    @Autowired
    private UserService userService200;
    public void sayOk() {
      System.out.println("userAction 装配的 userService属性=" + userService);
      userService200.hi();
    }
} @Qualifier与@AutoWired

必须搭配使用,相当于@Resource
https://i-blog.csdnimg.cn/direct/23b0847999cc477aabe433413cd6c14d.png
@Resource

https://i-blog.csdnimg.cn/direct/088fc3ee00d24ba3a8295a9fa3469454.png
 按照name的值在容器中查找,属性名没有作用了
https://i-blog.csdnimg.cn/direct/f64c406818f142d3a58062250f6150b2.png
按照type类型查找,属性名没有作用了,要求在容器里只能有一个如许类型的对象 
  https://i-blog.csdnimg.cn/direct/132ecae654594dd0afdc2deec66d3ff3.png
假如没有指定name和type,则先试用byName注入策略,假如匹配不上,再使用byType策略
https://i-blog.csdnimg.cn/direct/5f9d3c4cb152469a9b4f77ea68929054.png
泛型依靠装配

https://i-blog.csdnimg.cn/direct/3c24b3f2c1d54057858549ac084c0e5f.png
https://i-blog.csdnimg.cn/direct/d8f3693caaec4ec8b9571cd6632a6822.png
https://i-blog.csdnimg.cn/direct/caa1386113b74f45981664ac8ae643f0.png
https://i-blog.csdnimg.cn/direct/08eacec2a3e54e4a9c7d23baeba4e24c.png


https://i-blog.csdnimg.cn/direct/d11052470409454892fa18840c79dc93.png
https://i-blog.csdnimg.cn/direct/218c886dbe3d41199abe71c48eebf896.png
https://i-blog.csdnimg.cn/direct/36bda53dc34e417b901ba7616717823f.png
https://i-blog.csdnimg.cn/direct/0aa3bd06995441cd89e4a05a45553149.png
           使用Autowired
        把PhoneDao对象装配到PhoneService,通过泛型传入BaseDao,再把指定的泛型对象装配到PhoneService

动态署理 

不改变原有代码的情况下举行对象功能加强,使用署理对象拓展功能
public interface Vehicle {
    public void run();
    public String fly(int height);
} public class Car implements Vehicle{
    @Override
    public void run() {
      //System.out.println("交通工具开始运行了....");
      System.out.println("小汽车在路上 running....");
      //System.out.println("交通工具停止运行了....");
    }

    @Override
    public String fly(int height) {
      System.out.println("小汽车可以飞翔 高度=" + height);
      return "小汽车可以飞翔 高度=" + height;
    }
}  类似切面类

public class VehicleProxyProvider {
   
    //target_vehicle 表示真正要执行的对象
    //该对象的类实现了Vehicle接口
    private Vehicle target_vehicle;
   
    public VehicleProxyProvider(Vehicle target_vehicle) {
      this.target_vehicle = target_vehicle;
    }

    //编写一个方法,可以返回一个代理对象, 该代理对象可以通过反射机制调用到被代理对象的方法
    public Vehicle getProxy() {
      
      ClassLoader classLoader =
                target_vehicle.getClass().getClassLoader();

      //得到对象的接口信息
      Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();


      //创建InvocationHandler 对象
      //因为 InvocationHandler 是接口,所以我们可以通过匿名对象的方式来创建该对象
      /**
         *
         * public interface InvocationHandler {
         *public Object invoke(Object proxy, Method method, Object[] args)
         *         throws Throwable;
         * }
         * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
         *
         */

      InvocationHandler invocationHandler = new InvocationHandler() {
            /**
             * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
             * @param o 表示代理对象
             * @param method 就是通过代理对象调用方法时,的哪个方法 代理对象.run()
             * @param args : 表示调用 代理对象.run(xx) 传入的参数
             * @return 表示 代理对象.run(xx) 执行后的结果.
             * @throws Throwable
             */
            @Override
            public Object invoke(Object o, Method method, Object[] args)
                  throws Throwable {

                System.out.println("交通工具开始运行了....");
                //method 是?: public abstract void com.hspedu.spring.proxy2.Vehicle.run()
                //target_vehicle 是? Ship对象
                //args 是null
                //这里通过反射+动态绑定机制,就会执行到被代理对象的方法
                Object result = method.invoke(target_vehicle, args);
                System.out.println("交通工具停止运行了....");
                return result;
            }
      };

      /*
          public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
          1. Proxy.newProxyInstance() 可以返回一个代理对象
          2. ClassLoader loader: 类的加载器.
          3. Class<?>[] interfaces 就是将来要代理的对象的接口信息
          4. InvocationHandler h 调用处理器/对象 有一个非常重要的方法invoke
         */
      Vehicle proxy =
                (Vehicle)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

      return proxy;
    }
} Test类 

    @Test
    public void proxyRun() {
      //创建VehicleProxyProvider对象, 并且我们传入的要代理的对象
      VehicleProxyProvider vehicleProxyProvider =
                new VehicleProxyProvider(new Car());
      //获取代理对象, 该对象可以代理执行方法
      //proxy的编译类型是 Vehicle, 运行类型是 class com.sun.proxy.$Proxy9
      Vehicle proxy = vehicleProxyProvider.getProxy();
      //当执行run方法时,会执行到 代理对象的invoke
      proxy.run();
      String result = proxy.fly(10000);
      System.out.println("result=" + result);
    } getProxy()的缺点

https://i-blog.csdnimg.cn/direct/a98b6380020e4720a6f6ea9943d9a8d7.png
   硬编码,功能不强,希望以方法的情势来实行一段业务
写成方法,耦合度高
    //在目标对象执行前执行
    public void before(Method method, Object[] args) {
      System.out.println("before-方法执行前-日志-方法名-" + method.getName() + "-参数 "
                + Arrays.asList(args)); //这里从AOP看,就是一个横切关注点-前置通知
    }

    //在目标对象执行后执行
    public void after(Method method, Object result) {
      System.out.println("after-方法执行正常结束-日志-方法名-" + method.getName() + "-结果result= "
                + result);//从AOP看, 也是一个横切关注点-返回通知
    } 举行解耦,写成AOP类,复用性差,不灵活,硬编码
public class HspAOP {
    public static void before(Method method, Object[] args) {}
    public static void after(Method method, Object result) {}
} AOP

面向切面编程
https://i-blog.csdnimg.cn/direct/cb0b0f115f1f4818851cc38c3e88a0cf.png
https://i-blog.csdnimg.cn/direct/041d447ed3b94712a8214e03dff5ae62.png
https://i-blog.csdnimg.cn/direct/244316ea4fc34d62ab4fd6650043c7a1.png
快速入门

 https://i-blog.csdnimg.cn/direct/06502a0d68384bd8873b57451188b3a4.pnghttps://i-blog.csdnimg.cn/direct/c081e2c824a6428b97d13d41f0baaa07.png

环绕通知可以将四个通知合并管理
public interface SmartAnimalable {
    //求和
    float getSum(float i, float j);
    //求差
    float getSub(float i, float j);
} @Component //使用@Component 当spring容器启动时,将 SmartDog注入到容器
public class SmartDog implements SmartAnimalable {
    @Override
    public float getSum(float i, float j) {
      float result = i + j;
      System.out.println("方法内部打印result = " + result);
      return result;
    }

    @Override
    public float getSub(float i, float j) {
      float result = i - j;
      System.out.println("方法内部打印result = " + result);
      return result;
    }
} 切面类 

   


[*]@Before(value = "") 表现前置通知        
value = "execution(public float spring.aop.aspectj.SmartDog.getSum(float, float)       
指定切入到哪个类的哪个方法  情势是: 访问修饰符 返回类型 全类名.方法名(形参列表)
[*]showBeginLog方法可以明白成就是一个切入方法
[*]JoinPoint joinPoint 在底层实行时,由AspectJ切面框架, 会给该切入方法传入 joinPoint对象,通过该方法,步伐员可以获取到 相关信息
@Aspect //表示是一个切面类
@Component //会注入SmartAnimalAspect到容器
public class SmartAnimalAspect {
    @Before(value = "execution(public float spring.aspectj.SmartDog.getSum(float, float))")
    public void showBeginLog(JoinPoint joinPoint) {
      //通过连接点对象joinPoint 可以获取方法签名
      //invoke(Object proxy, Method method, Object[] args)整合到joinPoint
      Signature signature = joinPoint.getSignature();
      System.out.println(signature.getName() + "-参数 "
                + Arrays.asList(joinPoint.getArgs()));
    }
} XML开启AOP功能

    <context:component-scan
            base-package="com.hspedu.spring.aop.aspectj"/>
    <!-- 开启基于注解的AOP功能 -->
    <aop:aspectj-autoproxy/> 假如不开启,.getClass()不会得到署理对象,只会得到当前运行的对象(相当于new)
Test类

    @Test
    public void smartDogTestByProxy() {
      ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans08.xml");
      //需要通过接口类型来获取到注入的SmartDog对象-就是代理对象
      SmartAnimalable smartAnimalable =
                ioc.getBean(SmartAnimalable.class);
      //SmartAnimalable smartAnimalable =
      //      (SmartAnimalable)ioc.getBean("smartDog");
      smartAnimalable.getSum(10, 2);
    }   从前是new一个对象,得到这个类的的署理对象
动态署理返回的对象是个署理对象,强转成接口的情势返回
Animal proxy =
        (Animal)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
(xml中开启AOP)如今通过接口类型获取的对象就是这个类的署理对象
细节

https://i-blog.csdnimg.cn/direct/5ecd11c127a249fc9520e6db08c33277.png
   按接口来获取,多个类实现了接口会报错
UsbInterface interface = ioc.getBean(UsbInterface.class);

interface是署理对象,获取Phone类的署理对象,getBean()就相当于之前的getPorxy()
UsbInterface interface = (UsbInterface)ioc.getBean(Phone.class);
UsbInterface interface = (UsbInterface)ioc.getBean("phone");
切入表达式

https://i-blog.csdnimg.cn/direct/802b22f2436d4afcab36ccc53285cba9.png

https://i-blog.csdnimg.cn/direct/13ca4a3608da4196ae0270987d166990.png
https://i-blog.csdnimg.cn/direct/2c8a3196d6974442901eec063e9dfbe0.png
重用

https://i-blog.csdnimg.cn/direct/d6fb7584e99448bf9c170d165f94e8d8.png

    //定义一个切入点, 在后面使用时可以直接引用, 提高了复用性
    @Pointcut(value = "execution(public float spring.aspectj.SmartDog.getSum(float, float)))")
    public void myPointCut() {}

    @Before(value = "myPointCut()")
    public void showBeginLog(JoinPoint joinPoint) {}

    @AfterReturning(value = "myPointCut()", returning = "res")
    public void showSuccessEndLog(JoinPoint joinPoint, Object res) {}

    @AfterThrowing(value = "myPointCut()", throwing = "throwable")
    public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {}
 

两种动态署理

jdk的Proxy

面向接口,只能加强实现类中接口中存在的方法
得到的对象是JDK署理对象的实例
天生的署理对象只能转换成接口不能转换成被署理类
 
Spring的CGlib

面向父类,可以加强父类的所有方法
得到的对象是被署理对象的子类

JoinPoint常用方法

https://i-blog.csdnimg.cn/direct/b0c1419eefa04bb7a362bf128248de3c.png
返回通知中获取结果

https://i-blog.csdnimg.cn/direct/440853e119614a3dbd5091e027fe5582.png
https://i-blog.csdnimg.cn/direct/aa09fa3b81b74cbc8d1c11757840324c.png
   在@AfterReturning 增加属性 , 比如 returning = "res",同时在切入方法增加 Object res
留意: returning = "res" 和 Object res 的 res名字一致
 非常通知中获取非常

https://i-blog.csdnimg.cn/direct/d77c3889ed8f4da2a81d0ede723d49f9.png
https://i-blog.csdnimg.cn/direct/8d83ca0daaca4b3995687ee1434814b2.png
环绕通知 

@Aspect
@Component
public class SmartAnimalAspect {
    //演示环绕通知的使用-了解
    //1. @Around: 表示这是一个环绕通知[完成其它四个通知的功能]
    //2. value = "execution(public float com.hspedu.spring.aop.aspectj.SmartDog.getSum(float, float)) 切入点表达式
    //3. doAround 表示要切入的方法 - 调用结构 try-catch-finally
    @Around(value = "execution(public float com.hspedu.spring.aop.aspectj.SmartDog.getSum(float, float))")
    public Object doAround(ProceedingJoinPoint joinPoint) {
      Object result = null;
      String methodName = joinPoint.getSignature().getName();
      try {
            //1.相当于前置通知完成的事情
            Object[] args = joinPoint.getArgs();
            List<Object> argList = Arrays.asList(args);
            System.out.println("AOP环绕通知[-前置通知]" + methodName + "方法开始了--参数有:" + argList);
            //在环绕通知中一定要调用joinPoint.proceed()来执行目标方法
            result = joinPoint.proceed();
            //2.相当于返回通知完成的事情
            System.out.println("AOP环绕通知[-返回通知]" + methodName + "方法结束了--结果是:" + result);
      } catch (Throwable throwable) {
            //3.相当于异常通知完成的事情
            System.out.println("AOP环绕通知[-异常通知]" + methodName + "方法抛异常了--异常对象:" + throwable);
      } finally {
            //4.相当于最终通知完成的事情
            System.out.println("AOP环绕通知[-后置通知]" + methodName + "方法最终结束了...");
      }
      return result;
    }
} 切面优先级

   假如同一个方法,有多个切面在同一个切入点切入,优先级如何控制
@order(value = n) 来控制,n 越小,优先级越高
前置通知通过@order来判断顺序
https://i-blog.csdnimg.cn/direct/0bcca3d36e47475085aa6c494666f318.png


基于XML配置AOP 

public interface SmartAnimalable {
    float getSum(float i, float j);
    float getSub(float i, float j);
} public class SmartDog implements SmartAnimalable {
    @Override
    public float getSum(float i, float j) {return result;}
    @Override
    public float getSub(float i, float j) {return result;}
} 切面类将注解全部去掉 
public class SmartAnimalAspect {
    public void showBeginLog(JoinPoint joinPoint) {}
    public void showSuccessEndLog(JoinPoint joinPoint, Object res) {}
    public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {}
    public void showFinallyEndLog(JoinPoint joinPoint) {}
} 测试类 
    @Test
    public void testAspectByXML() {
      ApplicationContext ioc = new ClassPathXmlApplicationContext("beans09.xml");
      SmartAnimalable smartAnimalable =
                ioc.getBean(SmartAnimalable.class);
      smartAnimalable.getSum(10, 2);
    } <?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: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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--使用XML配置,完成AOP编程-->
    <!--配置一个切面类对象-bean-->
    <bean class="com.hspedu.spring.aop.xml.SmartAnimalAspect" id="smartAnimalAspect"/>
    <!--配置一个SmartDog对象-bean-->
    <bean class="com.hspedu.spring.aop.xml.SmartDog" id="smartDog"/>
    <!--配置切面类, 细节一定要引入 xmlns:aop-->
    <aop:config>
      <!--配置切入点-->
      <aop:pointcut id="myPointCut" expression="execution(public float com.hspedu.spring.aop.xml.SmartDog.getSum(float, float)))"/>
      <!--配置切面的前置,返回, 异常, 最终通知-->
      <aop:aspect ref="smartAnimalAspect" order="10">
            <!--配置前置通知-->
            <aop:before method="showBeginLog" pointcut-ref="myPointCut"/>
            <!--返回通知-->
            <aop:after-returning method="showSuccessEndLog" pointcut-ref="myPointCut" returning="res"/>
            <!--异常通知-->
            <aop:after-throwing method="showExceptionLog" pointcut-ref="myPointCut" throwing="throwable"/>
            <!--最终通知-->
            <aop:after method="showFinallyEndLog" pointcut-ref="myPointCut"/>
            <!--配置环绕通知-->
            <!--<aop:around method=""/>-->
      </aop:aspect>
    </aop:config>
</beans>

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Spring2~~~