首页 > 编程语言 > 详细

java Spring复杂类型注入 注解开发 Spring整合JUnit单元测试 AOP(面向切面编程) 动态代理(原生,cglib)

时间:2021-03-04 23:07:36      阅读:43      评论:0      收藏:0      [点我收藏+]

复杂类型注入
    ? 数组类型[]
    ? 集合类型 List Set Map Properties
    <!--复杂类型注入-->    xml
    <bean id="complexModel" class="com.zhiyou100.pojo.ComplexObject">
        <!--数组类型注入-->
        <property name="arr">
            <array>
                <!--往arr属性中诸如具体的值 值可以注入一个也可以诸如多个 数量不限-->
                <value>Java</value>
                <value>C</value>
                <!--往arr中注入一个对象类型-->
                <ref bean="user1"></ref>
            </array>
        </property>
    
        <!--List类型注入-->
        <property name="myList">
            <list>
                <!--注入基本类型-->
    
                <value>Python</value>
                <value>PHP</value>
                <!--注入引用类型-->
                <ref bean="user2"></ref>
            </list>
        </property>
    
        <!--set类型注入-->
        <property name="mySet">
            <set>
                <!--注入基本类型-->
                <value>C++</value>
                <value>JavaScript</value>
                <!--注入引用类型-->
                <ref bean="user1"></ref>
            </set>
        </property>
    
        <!--Map类型注入-->
        <property name="myMap">
            <map>
                <!--注入基本类型-->
                <entry key="课程" value="英语"></entry>
                <entry key="专业" value="Java"></entry>
                <!--注入引用类型-->
                <entry key="计算机系" value-ref="user1"></entry>
            </map>
        </property>
    
        <!--注入Properties-->
        <property name="properties">
            <props>
                <prop key="sex">男</prop>
                <prop key="gender">女</prop>
                <prop key="sexuality">未知</prop>
            </props>
        </property>
备注:
    以上使用的复杂类型,只要他存储结构相同,里面嵌套的标签可以混搭
    如::Array,List,Set单列的结构,他们里面的子标签可以混用
        Map,Properties双列结构,他们里面的子标签可以混用
Spring的分模块配置文件的开发
    有时候我们为了方便阅读,会将配置文件按照不同功能,模块分成多个xml文件,在引入的时候可以使用<import>标签,
集成到当前的配置文件中.目的就是当程序读取该配置文件,就会把引入的其他配置文件全部读进内存当中.
    注意事项:引入的时候,他是一个类路径(classes)也是一个相对路径
    不同的Spring的配置文件 格式:如dao层 applicationContext-dao.xml
                                    如service层 applicationContext-service.xml
                                    如web层 applicationContext-mvc.xml
                                    
    引入实例
    <imprt resource = "applicationContext-xxx.xml"/>
注解开发
    组件扫描
        ○ @Component
        ○ @Service
        ○ @Controller
        ○ @Repository
    配置步骤
        ○ 再主配置文件中applicationContext.xml文件中添加组件扫描
        <!--组件扫描 com.zhiyou100-->    xml
        <context:component-scan base-package="com.zhiyou100"/>
        备注:他不但能扫描当前包中的类,还能扫描到他的子包中的类
        ○ 在该包下,需要被Spring扫描的类上面添加注解 @Component@Service@Controller@Repository 中的任何一个即可
        ○ 别名:在注解后面加括号里写别名
        
    备注:
        想要让Spring容器扫描到注入的类,那么就需要在该类上面添加这四个注解中的任意一个,否则无法正常注入.
    就类似于给该类打上一个标记
        这四个注解,如果不指定对象名字,系统默认分配一个名字,名字格式为:首字母小写;
        但是如果在使用注解时,手动指定对象名字,那么将来获取该对象通过指定的名字获取.
    
@Scope注解配置对象的创建方式
    @Scope(scopeName = "singleton")指定该对象在单例模式下创建对象,返回的都是同一个对象
    @Scope(scopeName = "prototype")指定该对象在多例模式下创建对象,每次返回的都是新对象
    
    生命周期方法
        ○ @PostConstruct  标记在初始化方法上面,构造方法执行之后调用
        ○ @PreDestroy  标记在销毁的方法上面,容器关闭前销毁
    User类 pojo
//定义初始化方法
    @PostConstruct
    public void initUser(){
        System.out.println("构造方法调用后初始化该对象信息");
    }
    
    //定义销毁的方法
    @PreDestroy
    public void destroyUser(){
        System.out.println("容器关闭前销毁该对象");
    }
    备注:
    如果想要执行销毁方法,那么需要手动关闭容器,才能看到销毁方法被调用
    必须在单例模式种才支持
    //关闭容器
    ((ClassPathXmlApplicationContext)context).close();
    
    属性注入的注解
        ○ 简单类型=基本类型+String字符串类型
        @Value 注入属性值
        备注:该注解可以标记在属性上面,也可以标记在属性对应的set方法上面
        ○ 引用类型
            § @Autowired
            根据容器中的类型进行自动匹配,进行注入.一般情况下如果Spring容器中有多个该类型,那么就会报期望的值和从容其中查到的值数量不匹配
            //No qualifying bean of type ‘com.zhiyou100.pojo.User‘ available: expected single matching bean but found 3: user1,user2,user
            § @Qualifier
            指定该属性引用容器中的哪一个Bean对象,@Autowired和@Qualifier搭配使用.
            项目中,如果该类只在容器中配置一次,那么可以放心的使用@Autowired
            § @Resource
            相当于@Autowired+@Qualifier
            对于引用类型直接指定该属性注入哪个Bean对象
    Spring纯注解开发
        ○ @Configuration
        该注解是一个配置性的注解,指定当前类是一个Spring配置类
        @Configuration
public class SpringConfiguration{

}
        ○ @ComponentScan
        组件扫描注解 替代
        <context:component-scan base-package="com.zhiyou100"/>
        @Configuration
        @ComponentScan("com.zhiyou100")//存放的是组件扫描的包名
public class SpringConfiguration{

}
        ○ @Bean
        该注解只能写在方法上面,表明调用此方法会给你返回一个对象,存放到Spring容器中
        等价于:
        <bean id="car1" class="com.zhiyou100.pojo.Car" p:name="自行车" p:price="10"/>
        public class DBUtil{
                //使用CSP0
                private final static DataSource dataSource = new ComboPooledDataSource();
                @Bean
                public static Connection getConnection() throws SQLException {
                        return dataSource.getConnection();
                    }
        }
        ○ @PropertySource
        作用:主要是加载db.properties
        @PropertySource("db.properties")
public class DBUtil{
                @Value("${jdbc.driverClass}")
                private String driver;
                @Value("${jdbc.username}")
                private String url
                …
                
                //创建一个连接
                @Bean
                public static Connection getConnection() throws SQLException {
                        DataSource dataSource = new ComboPooledDataSource();
                        ComboPooledDataSource dataSource = new ComboPooledDataSource();
                                dataSource.setJdbcUrl(driver);
                                dataSource.setUser(url);
                        
                        return dataSource.getConnection();
                    }
                
                
        }
        db.properties
        jdbc.driver=com.mysql.jdbc.Driver
        jdbc.url=jdbc:mysql:///mybatis01?characterEncoding=UTF-8
        jdbc.username=root
        jdbc.password=root
        
        ○ @Import
        作用:主要导入其他配置文件.导入配置类
        等价于:
        <import resource="applicationContext-service.xml"/>
        @PropertySource("db.properties")
public class DBUtil{
                @Value("${jdbc.driverClass}")
                private String driver;
                @Value("${jdbc.username}")
                private String url
                …
                
                //创建一个连接
                @Bean
                public static Connection getConnection() throws SQLException {
                        DataSource dataSource = new ComboPooledDataSource();
                        ComboPooledDataSource dataSource = new ComboPooledDataSource();
                                dataSource.setJdbcUrl(driver);
                                dataSource.setUser(url);
                        
                        return dataSource.getConnection();
                    }
        }
        
        主配置类
        @Configuration
        @ComponentScan("com.zhiyou100")//存放的是组件扫描的包名
        @Import(DBUtil.class)
public class SpringConfiguration{

}
        //测试  不能使用因为他是加载xml文件用的
        ClassPathXmlApplicationContext("applicationContext.xml");
        @Test
        public void test01(){
                ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class)
                context.getBean("bean元素对象名",对应字节码文件)
        }
Spring整合JUnit单元测试
 作用:
    减少测试中不停的构建Spring容器,如以下代码,就可以省略掉
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class)
    context.getBean("bean元素对象名",对应字节码文件);
开发步骤:
    ? 在pom.xml文件中添加spring-test 坐标依赖
    ? 在测试类上添加注解@RunWith(SpringJUnit4ClassRunner.class)该类SpringJUnit4ClassRunner类由他帮助我们创建Spring容器
    ? 在测试类上面添加注解@ContextConfiguration("classpath:applicationContext.xml")注意:此路径是一个类路径,也是一个相对路径
    ? 从容器中取出需要的bean元素
    getBean()
    采用注解的属性注入@Autowired @Resource
    ? 测试是否成功


AOP(面向切面编程)
Aspect Oriented Programming,也是一种编程思想,主要的工作就是对应用中的重复代码进行横向抽取
在运行过程中采用动态代理技术把一些代码内容植入到应用当中.目标方法中进行一个增强.
Spring中有两种代理模式
静态代理
JDK原生的 动态代理
//JDK 原生的
//主要是对应用当中的业务层进行增强
//Proxy jdk的一个代理类
//使用该类中的一个方法newProxyInstance()
//该方法中有三个参数
    //ClassLoader:类加载器: 要求和目标对象是一样的类加载器  固定写法
    //Class<?> interfaces: 实现的接口,要求和目标对象中实现的接口一样  固定写法
    //InvocationHandle: 代理的方式 如何对目标对象进行增强 接口 匿名内部类
    //在该接口当中定义了一个抽象方法 invoke()
        //在该方法中也有三个参数:
        /*
            Object proxy:代理的目标对象
            Method method:当前要执行的,目标对象中的方法
            Object[] args:当前执行方法中用到的参数.
         */
代码示例:
原方法:
public User queryUserByUsername(String username){
    //......
        System.out.println("----------------------");
    //......
    return null;
}
原生动态代理
public UserService getProxyUserService(UserService userService){//UserService  接口  传入的参数值肯定是该接口的实现类
    UserService us = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("queryUserByUsername该方法开始执行了...");
            Object obj = method.invoke(userService, args);//反射机制
            System.out.println("queryUserByUsername该方法执行即将关闭...");
            return obj;
        }
    });
    return us;
}
测试
public static void main(String[] args){
    Proxy01 proxy01 = new Proxy01();
    UserService proxyUserService = proxy01.getProxyUserService(new UserServiceImpl());
    User user = proxyUserService.queryUserByUsername("小苏");
    System.out.println(user);
}
运行结果:
queryUserByUsername ÷     ??    ...
----------------------
queryUserByUsername ÷   ? м    ? ...
null


第三方插件 cglib代理
/*
    测试  动态代理  第二种方式 cglib
    原理  不需要借助接口,一般情况下在继承关系中--->父子类
    要求  目标类 不能是最终类  public final DemoClass{} 不能出现final
    Enhancer  增强器类
    create()  创建
    参数:
        class 字节码对象 目标对象中的字节码对象
        callback  ---> MethodInterceptor接口  方法拦截器 代理的方式
                        通过拦截器的方式实现对目标对象中的方法进行增强
        采用匿名内部类的方式实现
        MethodInterceptor定义了一个抽象方法
                intercept()  拦截方法
        拦截方法也有三个参数:
            Object proxy:  代理的目标对象
            Method method:  当前要执行的目标对象中的方法
            Object[] objects: 当前执行方法中用到的参数
 */
示例代码
原方法:
public User queryUserByUsername(String username){
    //......
        System.out.println("----------------------");
    //......
    return null;
}
cglib动态代理
public UserService getProxyUserService(UserService us){
    //us.getClass()获取字节码对象
    UserService userService = (UserService)Enhancer.create(us.getClass(), new MethodInterceptor() {
        //intercept拦截器
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("开启事务");//connection.setAutoCommit()
            Object obj = method.invoke(us, objects);
            System.out.println("提交事务");//commit()
            return obj;
        }
    });
    return userService;
}
JUnit测试:
@Test
public void test02(){
    UserService proxyUserService = proxy02.getProxyUserService(userService);
    User user = proxyUserService.queryUserByUsername("小孙");
    System.out.println(user);
}
测试结果:
开启事务
----------------------
提交事务
null

java Spring复杂类型注入 注解开发 Spring整合JUnit单元测试 AOP(面向切面编程) 动态代理(原生,cglib)

原文:https://www.cnblogs.com/shangjinshuai/p/14483005.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!