一.Spring AOP

  1.1 Spring AOP

底层还是用的动态代理。如果目标对象所对应的类有接口,spring就用jdk生成代理对象;

如果目标对象所对应的类没有接口,spring就用CGLIB生成代理对象。

优点:动态代理,如果一个类被它代理,则接口或者类的所有方法都被强迫执行。而spring AOP可以按业务划分,有些方法需要事务则扩展功能,有些方法不需要则不进行扩展。

1.2 相关概念名词

① 切面aspect:切面是一个类(功能类),类里有若干方法,每个方法代表一个功能。把这些功能方法切到指定的位置,切到到业务方法的前后等

对应:spring中<aop:aspect id="myAspect" ref="tm"></aop:aspect>

② 连接点joinpoint:用代理对象调用方法,这句话的位置就是连接点,用连接点启动横切。

③ 通知advice:切面类中的那些方法就是通知。

       前置通知<aop:before                在执行目标方法前面

后置通知<aop:after-returning    在执行完目标方法后执行

异常通知<aop:after-throwing    在目标方法抛异常执行,不会执行后置通知

最终通知<aop:after                   前置,后置或异常通知,都执行完毕后会执行最终通知

环绕通知<aop:around               特点:可以控制目标方法的执行

④ 切入点pointcut:把切面中的通知,切到哪个类中的哪些方法上,切入点是指切到哪些方法上,spring给提供一些规则表达式,用于指定切在哪些方法上。

对应:spring中<aop:pointcut id="myPointCut" expression="execution(* com.hdu.service..*.*(..))"/>

⑤ 目标对象targetObject:实际的业务类的对象

⑥ aop代理aopproxy:由spring框架帮程序员用jdk或cglib生成代理对象,这个生成的过程被spring封装了。spring的独有配置,用于指定生成代理对象。

对应: spring中<aop:config></aop:config>

⑦ 织入weaving:也叫横切,把额外的功能用配置文件和注解的方式织入到业务中;取消配置文件和注解,就取消了织入,不影响原有业务流程

在spring中加入<aop:config节点,<aop:pointcut expression="",从spring容器取出expression属性指定的对象都是代理对象。

在spring中没有加入<aop:config节点,从spring容器中取出的所有对象是真实对象。

    1.3 参考手册

1.3.1 声明一个切面

    

1.3.2 声明一个切点

    其中<aop:pointcut/>标签写在<aop:aspect></aop:aspect>标签内,为局部切点,只起作用在对应切面。

      

    其中<aop:pointcut/>标签写在<aop:aspect></aop:aspect>标签外,为全局切点,所有切面对其有效。

      

  关于切点的expression 表达式:

  

    参考手册中的示例:

      ① the execution of any public method:所有的public方法
        execution(public * *(..))
      ② the execution of any method with a name beginning with "set": 所有以set开头的方法
        execution(* set*(..))
      ③ the execution of any method defined by the AccountService interface: com.xyz.service.AccountService类或接口中任意方法,任意参数,任意返回值
        execution(* com.xyz.service.AccountService.*(..))
      ④ the execution of any method defined in the service package: com.xyz.service包下任意类,任意方法,任意参数,任意返回值
        execution(* com.xyz.service.*.*(..))
      ⑤ the execution of any method defined in the service package or a sub-package: com.xyz.service包下以及子包下任意类.任意的方法,任意参数,任意返回值
        execution(* com.xyz.service..*.*(..))

  关于切点的within表达式:

    ① any join point (method execution only in Spring AOP) within the service package:  com.xyz.service的任意类

      within(com.xyz.service.*)

     ② any join point (method execution only in Spring AOP) within the service package or a sub-package: com.xyz.service及其子包下的任意类

      within(com.xyz.service..*)

     ③ any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface: com.xyz.service的AccountService类

      this(com.xyz.service.AccountService)

1.3.3 声明通知

    通常 前置通知、后置通知、异常通知、最终通知 与 环绕通知分开使用,否则执行顺序不符合预期逻辑。

    若环绕通知叠加使用,按配置顺序先A后B,则执行时,先执行A在目标对象调用方法之前的内容,再执行B在目标对象调用方法之前的内容,调用目标对象的原有方法,执行A在目标对象调用方法之后的内容,执行B在目标对象调用方法之后的内容。

    1.3.3.1 前置通知

      

    1.3.3.2 后置通知

         

    1.3.3.3 异常通知

         

    1.3.3.4最终通知

      

    1.3.3.5环绕通知

      

二.Spring AOP使用示例:使用xml配置文件的方式

2.1 新增jar包,支持对AOP的处理

  2.2 接口及业务实现类

 package com.hdu.dao;

 public interface IUserDao {
     public int addrUser();
     public int updateUser();
 }

Interface IUserDao

 package com.hdu.dao.impl;

 import com.hdu.dao.IUserDao;

 public class UserDaoImpl implements IUserDao {

     @Override
     public int addrUser() {
         System.out.println("UserDaoImpl.addUser()");
         return 1;
     }

     @Override
     public int updateUser() {
         System.out.println("UserDaoImpl.updateUser()");
         return 1;
     }
 }

 Class UserDaoImpl

Class UserDaoImpl

 package com.hdu.service;

 public interface IUserService {
     public boolean addUser();
     public boolean updateUser();

 }

 Interface IUserService

Interface IUserService

 package com.hdu.service.impl;

 import com.hdu.dao.IUserDao;
 import com.hdu.dao.impl.UserDaoImpl;
 import com.hdu.service.IUserService;

 public class UserServiceImpl implements IUserService {
     //应该用spring进行解耦,本次重点在于代理,故简化操作
     private IUserDao userDao = new UserDaoImpl();

     @Override
     public boolean addUser() {
         System.out.println("UserServiceImpl.addUser()");
         boolean flag = false;
         int rowAffect = userDao.addrUser();
         if(rowAffect==1) {
             flag = true;
         }
         return flag;
     }

     @Override
     public boolean updateUser() {
         System.out.println("UserServiceImpl.updateUser()");
         boolean flag = false;
         int rowAffect = userDao.updateUser();
         if(rowAffect==1) {
             flag = true;
         }
         return flag;
     }

 }

 Class UserServiceImpl

Class UserServiceImpl

 2.3 切面类

其中JoinPoint 可以获取目标对象,目标方法及目标方法的参数,环绕通知则使用ProceedingJoinPoint 获取。

 package com.hdu.aspect;

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

 /**
  * 切面
  * @author Administrator
  *
  */
 public class TransactionManager {
     //前置通知方法
     public void begin(JoinPoint jp) {
         System.out.println("begin transaction");
         System.out.println("目标对象-->"+jp.getTarget());
         System.out.println("目标方法-->"+jp.getSignature().getName());
         System.out.println("目标方法参数-->"+jp.getArgs()[0]);
     }

     //后置通知方法
     public void commit(JoinPoint jp,Object flag) {
         System.out.println("commit transaction");
         System.out.println("目标对象-->"+jp.getTarget());
         System.out.println("目标方法-->"+jp.getSignature().getName());
         System.out.println("目标方法参数-->"+jp.getArgs()[0]);
         System.out.println("目标方法的返回值-->"+flag);
     }
     //异常通知方法
     public void rollback(JoinPoint jp,Exception ex) {
         System.out.println("rollback transaction");
         System.out.println("目标对象-->"+jp.getTarget());
         System.out.println("目标方法-->"+jp.getSignature().getName());
         System.out.println("目标方法参数-->"+jp.getArgs()[0]);
         System.out.println("目标方法抛异常-->"+ex.getMessage());
     }
     //最终通知
     public void finallyClose(JoinPoint jp) {
         System.out.println("finallyClose");
         System.out.println("目标对象-->"+jp.getTarget());
         System.out.println("目标方法-->"+jp.getSignature().getName());
         System.out.println("目标方法参数-->"+jp.getArgs()[0]);
     }
     //环绕通知  能控制目标方法的执行
     public Object around(ProceedingJoinPoint pjp)throws Throwable {
         Object retVal=null;
         try {
             System.out.println("around  begin transaction");
             System.out.println("目标对象-->"+pjp.getTarget());
             System.out.println("目标方法-->"+pjp.getSignature().getName());
             System.out.println("目标方法参数-->"+pjp.getArgs()[0]);
             //if() {
                 //就是直接指定目标方法
                 retVal = pjp.proceed();
             //}
             System.out.println("around  commit transaction");
         }catch(Exception e) {
             e.printStackTrace();
             System.out.println("around  rollback transaction");
         }finally {
             System.out.println("around  finallyClose");
         }

         return retVal;
     }
 }

2.4 配置文件

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

    <!-- 实例化业务模型对象 -->
    <bean id="userDao" class="com.hdu.dao.impl.UserDaoImpl"></bean>

    <bean id="userService" class="com.hdu.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>

    <!-- 实例化切面的对象 -->
    <bean id="tm" class="com.hdu.aspect.TransactionManager"></bean>

    <!-- spring 独有的配置,创建代理对象和确定如何横切切面 -->
    <!-- <aop:config>这个标签就告知spring要做代理对象了
            原则:如果实际对象有接口就jdk动态代理生成代理对象;如果实际对象没有接口就用cglib动态代理生成代理对象
             可以人为改动proxy-target-class="true",强制用cglib
    -->
    <aop:config proxy-target-class="false">
        <!-- <aop:aspect 这个节点标签,告知spring使用哪个切面
                可以写多个<aop:aspect节点,可以使用多个横切
        -->
        <aop:aspect id="myAspect" ref="tm">
            <!-- 告知spring 把切面 切在哪些类的哪些方法上,切点可以写多个-->
            <aop:pointcut id="myPointCut"
                          expression="execution(* com.hdu.service..*.*(..))"/>
            <!-- 前置通知 -->
            <aop:before
                pointcut-ref="myPointCut"
                method="begin"/>
            <!-- 后置通知
                属性returning="flag" flag对应的通知方法中的参数
            -->
            <aop:after-returning
                pointcut-ref="myPointCut"
                method="commit"
                returning="flag"/>
            <!-- 异常通知
                属性throwing="ex"  ex对应的异常通知的方法的参数
            -->
            <aop:after-throwing
                pointcut-ref="myPointCut"
                method="rollback"
                throwing="ex"/>

            <!-- 最终通知 -->
            <aop:after
                pointcut-ref="myPointCut"
                method="finallyClose"/>
            <!-- 环绕通知 -->
<!--              <aop:around -->
<!--                 pointcut-ref="myPointCut" -->
<!--                 method="around"/>         -->
        </aop:aspect> 

    </aop:config>    

</beans>

  2.5 测试

 package com.hdu.test;

 import org.junit.Test;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;

 import com.hdu.dao.UserDao;
 import com.hdu.entity.User;
 import com.hdu.service.UserService;

 public class TestSpringAOP {
     @Test
     public void testMethod1() {
         //初始化spring容器
         ApplicationContext context = new ClassPathXmlApplicationContext("resources/spring_aop.xml");
         UserService userService=context.getBean("userService",UserService.class);
         System.out.println(userService.getClass());
         userService.addUser(new User());

         //userDao不会被代理
         UserDao userDao=context.getBean("userDao",UserDao.class);
         System.out.print("userDao不会被代理"+userDao.getClass());
     }
 }

Test

  结果:

class com.sun.proxy.$Proxy6
begin transaction
目标对象-->com.hdu.service.impl.UserServiceImpl@769f71a9
目标方法-->addUser
目标方法参数-->com.hdu.entity.User@4b5d6a01
UserServiceImpl.addUser()
UserDaoImpl.addUser()
commit transaction
目标对象-->com.hdu.service.impl.UserServiceImpl@769f71a9
目标方法-->addUser
目标方法参数-->com.hdu.entity.User@4b5d6a01
目标方法的返回值-->true
finallyClose
目标对象-->com.hdu.service.impl.UserServiceImpl@769f71a9
目标方法-->addUser
目标方法参数-->com.hdu.entity.User@4b5d6a01
userDao不会被代理class com.hdu.dao.impl.UserDaoImpl

Conclusion

2.6调用过程

    我们获取对象,要么是对象地址,要么是代理:System.out.println(userService.getClass());

  从打印结果 class com.sun.proxy.$Proxy6 可知,目前使用的是jdk动态代理。

    其中UserService userService = (UserService) context.getBean("userService");执行时spring已经把UserService变成代理对象。

  在执行userService.addUser();业务方法时就会被invoke方法拦截。就被切点表达式expression="execution(* com.hdu.service..*.*(..))"拦截。

  切点表达式expression="execution(* com.hdu.service..*.*(..))"匹配上了实现类,就会执行切面中通知。

    <aop:aspect id="myAspect" ref="tm">

      <aop:before pointcut-ref="myPointCut" method="begin"/>

    </aop:aspect>

  就找到TransactionManager类,找到before方法,并调用。

  也就是说只要程序满足切点表达式,就会调用切面的方法。最终我们就看到它不是真实的对象,而是一个代理对象。由代理去执行就会响应执行通知的方法。

三.Spring AOP使用示例:使用注解的方式

3.1 切面类

  参考手册:

    

  切点可以是局部的也可以是全局的。

 package com.hdu.aspect;

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

 /**
  * 切面
  * @author Administrator
  *
  */
 @Component("tm")
 @Aspect
 public class TransactionManager {
     //the pointcut expression
     @Pointcut("execution(* com.hdu.service..*.*(..))")
     private void myPointCut() {}// the pointcut signature

     //前置通知方法
     //@Before("myPointCut()")
     public void begin(JoinPoint jp) {
         System.out.println("begin transaction");
         System.out.println("目标对象-->"+jp.getTarget());
         System.out.println("目标方法-->"+jp.getSignature().getName());
         System.out.println("目标方法参数-->"+jp.getArgs()[0]);
     }

     //后置通知方法
     //@AfterReturning(pointcut="myPointCut()",returning="flag")
     public void commit(JoinPoint jp,Object flag) {
         System.out.println("commit transaction");
         System.out.println("目标对象-->"+jp.getTarget());
         System.out.println("目标方法-->"+jp.getSignature().getName());
         System.out.println("目标方法参数-->"+jp.getArgs()[0]);
         System.out.println("目标方法的返回值-->"+flag);
     }
     //异常通知方法
     //@AfterThrowing(pointcut="myPointCut()",throwing="ex")
     public void rollback(JoinPoint jp,Exception ex) {
         System.out.println("rollback transaction");
         System.out.println("目标对象-->"+jp.getTarget());
         System.out.println("目标方法-->"+jp.getSignature().getName());
         System.out.println("目标方法参数-->"+jp.getArgs()[0]);
         System.out.println("目标方法抛异常-->"+ex.getMessage());
     }
     //最终通知
     //@After("myPointCut()")
     public void finallyClose(JoinPoint jp) {
         System.out.println("finallyClose");
         System.out.println("目标对象-->"+jp.getTarget());
         System.out.println("目标方法-->"+jp.getSignature().getName());
         System.out.println("目标方法参数-->"+jp.getArgs()[0]);
     }

     //环绕通知  能控制目标方法的执行
     @Around("myPointCut()")
     public Object around(ProceedingJoinPoint pjp)throws Throwable {
         Object retVal=null;
         try {
             System.out.println("around  begin transaction");
             System.out.println("目标对象-->"+pjp.getTarget());
             System.out.println("目标方法-->"+pjp.getSignature().getName());
             System.out.println("目标方法参数-->"+pjp.getArgs()[0]);
             //if() {
                 //就是直接指定目标方法
                 retVal = pjp.proceed();

             //}
             System.out.println("around  commit transaction");
         }catch(Exception e) {
             e.printStackTrace();
             System.out.println("around  rollback transaction");
         }finally {
             System.out.println("around  finallyClose");
         }

         return retVal;
     }
 }

    3.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--
        @Controller @Service @Repository @Component @Resource    @Autowired @Qualifier
     -->
    <!-- 实例化业务模型对象 -->
    <context:component-scan base-package="com.hdu.dao.impl"></context:component-scan>
    <context:component-scan base-package="com.hdu.service.impl"></context:component-scan>

    <!-- 实例化切面的对象 -->
    <context:component-scan base-package="com.hdu.aspect"></context:component-scan>

    <!-- spring 独有的配置,创建代理对象和确定如何横切切面
        @Aspect @Pointcut @Before @AfterReturning @AfterThrowing @After @Around
     -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

    3.3 测试

 package com.hdu.test;

 import org.junit.Test;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;

 import com.hdu.entity.User;
 import com.hdu.service.UserService;

 public class TestSpringAOP {
     @Test
     public void testMethod1() {
         //初始化spring容器
         ApplicationContext context= new ClassPathXmlApplicationContext("resources/spring_aop.xml");
         UserService userService=context.getBean("userService",UserService.class);
         System.out.println(userService.getClass());
         userService.addUser(new User());//连接点 启动横切
     }

 }

Test

结果

class com.sun.proxy.$Proxy13
around  begin transaction
目标对象-->com.hdu.service.impl.UserServiceImpl@217ed35e
目标方法-->addUser
目标方法参数-->com.hdu.entity.User@f5958c9
UserServiceImpl.addUser()
UserDaoImpl.addUser()
around  commit transaction
around  finallyClose

Conclusion

  

  

代理模式及Spring AOP (二)的更多相关文章

  1. Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式

    Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式 主题 概念 Hibernate 延迟加载的代理模式 Spring AOP的代理模式 区别和联系 静态代理和动态代理 概念 代 ...

  2. 代理模式及Spring AOP (一)

    一.代理模式 在不更改源码的前提下,加入新功能,通常需要用到代理设计模式. 代理设计模式分类: 静态代理 动态代理 jdk动态代理 cglib动态代理 其中spring AOP的底层用的是动态代理.其 ...

  3. 从代理模式到Spring AOP

    什么是代理模式 假如我喜欢上隔壁班的翠花,但是我没胆量向她送花,这时候我需要一个铁杆哥们帮我做这件事, 很明显这哥们是个代理,是去执行任务的,但是花实际上是我"送"的,代理和我一样 ...

  4. CgLib动态代理学习【Spring AOP基础之一】

    如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...

  5. Spring AOP(二)--注解方式

    本文介绍通过注解@AspectJ实现Spring AOP,这里要重点说明一下这种方式实现时所需的包,因为Aspect是第三方提供的,不包含在spring中,所以不能只导入spring-aop的包,为了 ...

  6. java代理课程测试 spring AOP代理简单测试

    jjava加强课程测试代码 反射. 代理 .泛型.beanUtils等 项目源码下载:http://download.csdn.net/detail/liangrui1988/6568169 热身运动 ...

  7. Java动态代理学习【Spring AOP基础之一】

    Spring AOP使用的其中一个底层技术就是Java的动态代理技术.Java的动态代理技术主要围绕两个类进行的 java.lang.reflect.InvocationHandler java.la ...

  8. 基于代理类实现Spring AOP

    目录 ProxyFactoryBean类介绍 基于JDK动态代理的Spring  AOP实现 基于CGLIB代理的Spring  AOP实现 Spring的通知类型 ProxyFactoryBean类 ...

  9. Spring AOP (二)

    下面介绍@AspectJ语法基础 一.切点表达式函数 AspectJ的切点表达式由关键字和操作参数组成,如execution(* greetTo(..)) 的切点表达式,execution为关键字,而 ...

随机推荐

  1. OpenGL入门程序三:点、线、面的绘制

    1.点: void TestPoint() { //点的大小默认为一个像素,通过下面的函数可以设置一点的大小 glPointSize(50.0f); glBegin(GL_POINTS); glVer ...

  2. python导包显示No module named XXX问题

    最近用sublime text写python脚本,在导包是一直显示No module named XXX. 问题描述: 首先文件夹的目录结构如下: count.py文件,代码如下: #coding=u ...

  3. ln软连接

    ln软连接 ln -s 源目录/文件    目标目录/文件 例如,有个应用 /var/www/html/webapp,下面有个logs日志文件夹,想吧  webapp/logs日志文件夹链到/home ...

  4. .NET中使用Rabbit MQ

    1.通过Nuget 获取Rabbit MQ NET client bindings from NuGet: PM> Install-Package RabbitMQ.Client 2.发送者(生 ...

  5. [NOI2018]你的名字(68pts)

    SAM真让人头秃. 题面 https://www.luogu.org/problemnew/show/P4770 首先考虑 l=1,r=∣S∣的做法 如果对于ION2018的子串不用判重的话,对ION ...

  6. django-rest-framework登陆认证

    # -*- coding: utf-8 -*- __author__ = 'YongCong Wu' # @Time : 2018/10/23 15:05 # @Email : : 192287802 ...

  7. Codeforces Round #449 (Div. 1)C - Willem, Chtholly and Seniorious

    ODT(主要特征就是推平一段区间) 其实就是用set来维护三元组,因为数据随机所以可以证明复杂度不超过O(NlogN),其他的都是暴力维护 主要操作是split,把区间分成两个,用lowerbound ...

  8. nyoj-677-最大流最小割

    677-碟战 内存限制:64MB 时间限制:2000ms 特判: No通过数:2 提交数:2 难度:4 题目描述: 知己知彼,百战不殆!在战争中如果被敌人掌握了自己的机密,失败是必然的.K国在一场战争 ...

  9. xhost + 的作用

    xhost 是用来控制X server访问权限的. 通常当你从hostA登陆到hostB上运行hostB上的应用程序时, 做为应用程序来说,hostA是client,但是作为图形来说, 是在hostA ...

  10. 一、final关键字

    final关键字修饰:类,方法,基本类型变量,引用,具有不同的意思 1.final修饰类 表示该类不能被继承 package property; public final class Hero ext ...