博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring学习(二)
阅读量:4022 次
发布时间:2019-05-24

本文共 19507 字,大约阅读时间需要 65 分钟。

Spring学习笔记(
9
)----让Spring自动扫描和管理Bean
-------------------------------------------------
 
 
 
Java代码 
1
.
package 
com.szy.spring.service; 
2
3
.
import 
org.springframework.stereotype.Service; 
4
5
.
import 
com.szy.spring.dao.PersonDao; 
6
.
@Service
(
"service"
7
.
public 
class 
UserServiceImpl
implements 
UserService 
8
.{ 
9
.   
private 
PersonDao personDaoBean; 
10
.     
11
.   
public 
void 
show() 
12
.    { 
13
.        personDaoBean.show(); 
14
.    } 
15
16
.   
public 
void 
setPersonDaoBean(PersonDao personDaoBean) 
17
.    { 
18
.       
this
.personDaoBean = personDaoBean; 
19
.    } 
20
.} 
  
 
在前面的例子中,都是使用XML的bean定义来使用组件,在大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会使配置文件显得很臃肿,查找和维护起来不方便。Spring2.
5
为我们引入了组件自动扫描机制,它可以在类路径下寻找标记了
@Component
@Service
@Controller
@Repository
注解的类,并把这些类纳入到spring容器中管理,它的作用和在xml中使用bean节点配置组件一样。要使用自动扫描机制,我们需要把配置文件如下配置:
  
 
 
Xml代码 
1
.<?xml version=
"1.0" 
encoding=
"UTF-8"
?> 
2
.<beans xmlns=
"http://www.springframework.org/schema/beans" 
3
.    xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance" 
4
.    xmlns:context=
"http://www.springframework.org/schema/context" 
5
.    xmlns:tx=
"http://www.springframework.org/schema/tx" 
6
.    xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
7
.                http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 
8
.                http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
9
.    <context:component-scan base-
package
=
"com.szy.spring"
></context:component-scan> 
10
.</beans> 
  
 
其中base-
package
为需要扫描的包(包括子包)
  
@Service
用于标注业务层的组件,
@Controller
用于标注控制层组件(如struts中的action),
@Repository
用于标注数据访问组件,即DAO组件,而
@Component
泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。但是在目前的spring版本中,这几个注解的作用是一样的,但是在以后可能会进行区分。
  
  
  
下面把先前的例子修改一下:
  
首先是PersonDaoBean类,修改如下
  
 
 
Java代码 
1
.
package 
com.szy.spring.dao; 
2
3
.
import 
org.springframework.stereotype.Repository; 
4
5
.
@Repository 
6
.
//告诉spring这个类要交给spring管理, 
7
.
public 
class 
PersonDaoBean
implements 
PersonDao 
8
.{ 
9
.   
public 
void 
show() 
10
.    { 
11
.        System.out.println(
"执行PersonDaoBean中的add()方法"
); 
12
.    } 
13
.} 
  
  
  
然后是UserServiceImpl类
  
 
 
Java代码 
1
.
package 
com.szy.spring.service; 
2
3
.
import 
org.springframework.stereotype.Service; 
4
5
.
import 
com.szy.spring.dao.PersonDao; 
6
.
@Service 
7
.
//把这个类交给spring管理,作为服务了。 
8
.
public 
class 
UserServiceImpl
implements 
UserService 
9
.{ 
10
.   
private 
PersonDao personDaoBean; 
11
.     
12
.   
public 
void 
show() 
13
.    { 
14
.        personDaoBean.show(); 
15
.    } 
16
17
.   
public 
void 
setPersonDaoBean(PersonDao personDaoBean) 
18
.    { 
19
.       
this
.personDaoBean = personDaoBean; 
20
.    } 
21
22
.   
public 
PersonDao getPersonDaoBean() 
23
.    { 
24
.       
return 
personDaoBean; 
25
.    } 
26
.} 
  
  
  
  
  
 
下面我们进行测试,原来的测试代码是userServiceImpl
 
 
 
Java代码 
1
.ApplicationContext ctx=
new 
ClassPathXmlApplicationContext(
"applicationContext.xml"
); 
2
.        UserService service=(UserService)ctx.getBean(
"userService"
); 
3
.        service.show(); 
  
  
  
其中userService是我们在配置文件中配置的bean的id。但是如今我们并没有id这个属性,在spring2.
5
中,默认的id是类的名称,但是开后是小写,也就是userServiceImpl,因此测试代码应修改如下:
  
 
 
Java代码 
1
.AbstractApplicationContext ctx=
new 
ClassPathXmlApplicationContext(
"applicationContext.xml"
); 
2
.        UserService service=(UserService)ctx.getBean(
"userServiceImpl"
); 
3
.        System.out.println(service); 
  
  
  
如果我们想自己命名的话,则只需在注解后加上括号,里面写入你希望的名字,如
  
@Service
(
"userService"
)。
  
  
  
在spring中默认的是之生成一个bean实例,如果我们想每次调用都产生一个实例,则标注需如下配置
  
@Service 
@Scope
(
"prototype"
)
  
  
  
在xml中我们还可以配置初始化方法和销毁方法,使用标注后只需如下标注
  
 
 
Java代码 
1
.
@PostConstruct 
2
.   
public 
void 
init() 
3
.    { 
4
.        System.out.println(
"初始化"
); 
5
.    } 
6
.   
@PreDestroy 
7
.   
public 
void 
destory() 
8
.    { 
9
.        System.out.println(
"销毁"
); 
10
.    } 
  
  
  
 
使用注解后,我们的xml文件变得十分简单,因此建议Spring学习笔记(
10
)----公共属性的注入配置大家在以后的开发中使用注解。
 
 
 
 
 
 
 
 
 
 
Spring学习笔记(
10
)----公共属性的注入配置
-------------------------------------------
假设我们定义了四个bean类,其代码分别如下:
  
 
 
Java代码 
1
.
package 
com.szy.spring.bean; 
2
3
.
public 
class 
Bean1 { 
4
.   
private 
Bean2 bean2; 
5
.   
private 
Bean3 bean3; 
6
.   
private 
Bean4 bean4; 
7
8
.   
public 
Bean2 getBean2() 
9
.    { 
10
.       
return 
bean2; 
11
.    } 
12
.   
public 
void 
setBean2(Bean2 bean2) 
13
.    { 
14
.       
this
.bean2 = bean2; 
15
.    } 
16
.   
public 
Bean3 getBean3() 
17
.    { 
18
.       
return 
bean3; 
19
.    } 
20
.   
public 
void 
setBean3(Bean3 bean3) 
21
.    { 
22
.       
this
.bean3 = bean3; 
23
.    } 
24
.   
public 
Bean4 getBean4() 
25
.    { 
26
.       
return 
bean4; 
27
.    } 
28
.   
public 
void 
setBean4(Bean4 bean4) 
29
.    { 
30
.       
this
.bean4 = bean4; 
31
.    } 
32
.} 
  
  
  
  
  
 
 
Java代码 
1
.
package 
com.szy.spring.bean; 
2
3
.
public 
class 
Bean2 
4
.{ 
5
.   
private 
int 
id; 
6
.   
private 
String name; 
7
.   
private 
String password; 
8
9
.   
public 
int 
getId() 
10
.    { 
11
.       
return 
id; 
12
.    } 
13
.   
public 
void 
setId(
int 
id) 
14
.    { 
15
.       
this
.id = id; 
16
.    } 
17
.   
public 
String getName() 
18
.    { 
19
.       
return 
name; 
20
.    } 
21
.   
public 
void 
setName(String name) 
22
.    { 
23
.       
this
.name = name; 
24
.    } 
25
.   
public 
String getPassword() 
26
.    { 
27
.       
return 
password; 
28
.    } 
29
.   
public 
void 
setPassword(String password) 
30
.    { 
31
.       
this
.password = password; 
32
.    } 
33
.} 
  
  
  
  
  
 
 
Java代码 
1
.
package 
com.szy.spring.bean; 
2
3
.
public 
class 
Bean3 
4
.{ 
5
.   
private 
int 
id; 
6
.   
private 
String name; 
7
8
.   
public 
int 
getId() 
9
.    { 
10
.       
return 
id; 
11
.    } 
12
.   
public 
void 
setId(
int 
id) 
13
.    { 
14
.       
this
.id = id; 
15
.    } 
16
.   
public 
String getName() 
17
.    { 
18
.       
return 
name; 
19
.    } 
20
.   
public 
void 
setName(String name) 
21
.    { 
22
.       
this
.name = name; 
23
.    } 
24
.} 
  
  
  
  
  
 
 
Java代码 
1
.
package 
com.szy.spring.bean; 
2
3
.
public 
class 
Bean4 
4
.{ 
5
.   
private 
int 
age; 
6
7
.   
public 
int 
getAge() 
8
.    { 
9
.       
return 
age; 
10
.    } 
11
.   
public 
void 
setAge(
int 
age) 
12
.    { 
13
.       
this
.age = age; 
14
.    } 
15
.} 
  
  
  
按照正常的思路,我们下面就要给每个类进行属性的注入,配置文件如下设置:
  
 
 
Xml代码 
1
.<?xml version=
"1.0" 
encoding=
"UTF-8"
?> 
2
.<beans xmlns=
"http://www.springframework.org/schema/beans" 
3
.    xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance" 
4
.    xmlns:context=
"http://www.springframework.org/schema/context" 
5
.    xmlns:tx=
"http://www.springframework.org/schema/tx" 
6
.    xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
7
.                http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 
8
.                http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
9
.    <bean id=
"bean1" 
class
=
"com.szy.spring.bean.Bean1"
10
.        <property name=
"bean2" 
ref=
"bean2"
/> 
11
.        <property name=
"bean3"
12
.            <ref bean=
"bean3"
/> 
13
.        </property>    
14
.        <property name=
"bean4" 
ref=
"bean4"
/> 
15
.    </bean> 
16
.     
17
.    <bean id=
"bean2" 
class
=
"com.szy.spring.bean.Bean2"
18
.        <property name=
"id" 
value=
"100"
/> 
19
.        <property name=
"name"
20
.            <value>kuka</value> 
21
.        </property> 
22
.        <property name=
"password" 
value=
"123"
/> 
23
.    </bean> 
24
.     
25
.    <bean id=
"bean3" 
class
=
"com.szy.spring.bean.Bean3"
26
.        <property name=
"id" 
value=
"100"
/> 
27
.        <property name=
"name" 
value=
"kuka"
/> 
28
.    </bean> 
29
.      
30
.    <bean id=
"bean4" 
class
=
"com.szy.spring.bean.Bean4"
31
.        <property name=
"age" 
value=
"22"
/> 
32
.    </bean> 
33
.</beans> 
  
  
  
我们进行测试:
  
 
 
Java代码 
1
.
@Test 
2
.   
public 
void 
testMethod()
throws 
Exception 
3
.    { 
4
.        ApplicationContext ctx=
new 
ClassPathXmlApplicationContext(
"applicationContext.xml"
); 
5
.        Bean1 bean1 = (Bean1)ctx.getBean(
"bean1"
); 
6
.         
7
.        System.out.println(
"bean1.bean2.id=" 
+ bean1.getBean2().getId()); 
8
.        System.out.println(
"bean1.bean2.name=" 
+ bean1.getBean2().getName()); 
9
.        System.out.println(
"bean1.bean2.password=" 
+ bean1.getBean2().getPassword()); 
10
.        System.out.println(
"bean1.bean3.id=" 
+ bean1.getBean3().getId()); 
11
.        System.out.println(
"bean1.bean3.name=" 
+ bean1.getBean3().getName()); 
12
.        System.out.println(
"bean1.bean4.age=" 
+ bean1.getBean4().getAge()); 
13
.    } 
  
  
  
正常输出我们所预期的信息,但是我们观察发现bean2和bean3的部分属性的配置信息是相同的,这仅是两个bean,如果是多个bean的话我们要修改就好修改多处,因此我们可以把这些公共的部分提出出来,进行抽象。这个在Spring中是支持的。我们在建立一个配置文件,命名为:applicationCommon.xml,其内容如下配置
  
 
 
Xml代码 
1
.<?xml version=
"1.0" 
encoding=
"UTF-8"
?> 
2
.<beans xmlns=
"http://www.springframework.org/schema/beans" 
3
.    xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance" 
4
.    xmlns:context=
"http://www.springframework.org/schema/context" 
5
.    xmlns:tx=
"http://www.springframework.org/schema/tx" 
6
.    xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
7
.                http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 
8
.                http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
9
.     <bean id=
"beanAbstract" 
abstract
=
"true"
10
.        <property name=
"id" 
value=
"100"
/> 
11
.        <property name=
"name" 
value=
"kuka"
/> 
12
.   </bean>          
13
.    
14
.   <bean id=
"bean2" 
class
=
"com.szy.spring.bean.Bean2" 
parent=
"beanAbstract"
15
.            <property name=
"password" 
value=
"123"
/> 
16
.   </bean>         
17
.    
18
.   <bean id=
"bean3" 
class
=
"com.szy.spring.bean.Bean3" 
parent=
"beanAbstract"
/> 
19
.     
20
.</beans> 
  
 
beanAbstract就是我们抽象出来的,设置
abstract
=
"true"
属性后就不需要指定
class
属性。
  
我们把原来配置文件里的关于bean2和bean3节点注释掉。
  
下面进行测试,在这里要注意由于我们使用了两个配置文件,因此我们在读取是要写两个配置文件名。我们查看ClassPathXmlApplicationContext源文件发现其有个构造函数参数是string数组,因此我们可以把这个配置文件名放在数组里面。此外我们还有另外一种实现方法,两个配置文件一个叫applicationContext.xml,另一个applicationCommon.xml,公共部分是applicationC*.xml,下面我们就可以这样进行测试:
  
 
 
Java代码 
1
.
@Test 
2
.   
public 
void 
testMethod()
throws 
Exception 
3
.    { 
4
.        ApplicationContext ctx=
new 
ClassPathXmlApplicationContext(
"applicationC*.xml"
); 
5
.        Bean1 bean1 = (Bean1)ctx.getBean(
"bean1"
); 
6
.         
7
.        System.out.println(
"bean1.bean2.id=" 
+ bean1.getBean2().getId()); 
8
.        System.out.println(
"bean1.bean2.name=" 
+ bean1.getBean2().getName()); 
 
 
9
.        System.out.println(
"bean1.bean2.password=" 
+ bean1.getBean2().getPassword()); 
10
.        System.out.println(
"bean1.bean3.id=" 
+ bean1.getBean3().getId()); 
11
.        System.out.println(
"bean1.bean3.name=" 
+ bean1.getBean3().getName()); 
12
.        System.out.println(
"bean1.bean4.age=" 
+ bean1.getBean4().getAge()); 
13
.    } 
  
  
  
如果我们bean2的name属性的值不是kuka,那么我们只需在applicationCommon.xml文件的bean2节点下再添加property属性即可
  
 
 
Xml代码 
1
.<property name=
"name" 
value=
"coolszy"
/> 
 
 
 
 
 
 
 
 
 
 
 
 
Spring学习笔记(
11
)----自定义属性编辑器
-------------------------------------------
前面我们所定义的属性都是几本的属性,如果我们定义一个属性是Date类型,例如如下类中:
  
 
 
Java代码 
1
.
package 
com.szy.spring.bean; 
2
3
.
import 
java.util.Date; 
4
5
.
public 
class 
Bean { 
6
.   
private 
Date date; 
7
8
.   
public 
Date getDate() 
9
.    { 
10
.       
return 
date; 
11
.    } 
12
.   
public 
void 
setDate(Date date) 
13
.    { 
14
.       
this
.date = date; 
15
.    } 
16
.} 
  
 
按照我们以前学过的知识我们需要在配置文件中给该属性注入值
  
 
 
Xml代码 
1
.<bean id=
"bean" 
class
=
"com.szy.spring.bean.Bean"
2
.        <property name=
"date" 
value=
"2009-11-21"
/> 
3
.    </bean> 
  
 
下面我们测试是否成功注入值
  
 
 
Java代码 
1
.ApplicationContext ctx=
new 
ClassPathXmlApplicationContext(
"applicationContext.xml"
); 
2
.        Bean bean = (Bean)ctx.getBean(
"bean"
); 
3
.        System.out.println(bean.getDate()); 
  
 
运行包如下异常
  
 
 
Exception代码 
1
.org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'bean' 
defined in
class 
path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [java.util.Date]
for 
property
'date'
; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [java.util.Date]
for 
property
'date'
: no matching editors or conversion strategy found 
  
 
通过错误提示信息我们得知spring不能将string转换成date类型,没有匹配的编辑器或者转换机制。
如果想实现string转换成Date,那么我们自己需要写一个属性编辑器
  
我们新建一个类DatePropertyEditor,这个类要继承PropertyEditorSupport类。
我们需要复写这个类中的setAsText方法,其中text参数就是配置文件中的值。我们的任务就是把text转换成date类型的值。
  
 
 
Java代码 
1
.
package 
com.szy.spring.util; 
2
3
.
import 
java.beans.PropertyEditorSupport; 
4
.
import 
java.text.SimpleDateFormat; 
5
.
import 
java.util.Date; 
6
7
.
public 
class 
DatePropertyEditor
extends 
PropertyEditorSupport 
8
.{ 
9
10
.   
@Override 
11
.   
public 
void 
setAsText(String text)
throws 
IllegalArgumentException 
12
.    { 
13
.        String format=
"yyyy-MM-dd"
14
.        SimpleDateFormat sdf=
new 
SimpleDateFormat(format); 
15
.       
try 
16
.        { 
17
.            Date date=sdf.parse(text); 
18
.           
this
.setValue(date); 
//把转换后的值传过去 
19
.        }
catch 
(Exception e) 
20
.        { 
21
.            e.printStackTrace(); 
22
.        } 
23
.    } 
24
25
.} 
  
写完编辑器后我们还需要把编辑器注入到spring中。 为了方便管理我们再新建一个配置文件applicationEditor.xml,用来配置属性编辑器
  
 
 
Xml代码 
1
.<?xml version=
"1.0" 
encoding=
"UTF-8"
?> 
2
.<beans xmlns=
"http://www.springframework.org/schema/beans" 
3
.    xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance" 
4
.    xmlns:context=
"http://www.springframework.org/schema/context" 
5
.    xmlns:tx=
"http://www.springframework.org/schema/tx" 
6
.    xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
7
.                http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 
8
.                http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
9
.    <bean id=
"customEditorConfigurer" 
class
=
"org.springframework.beans.factory.config.CustomEditorConfigurer"
10
.        <!-- 把值注入到CustomEditorConfigurer的 Map类型的customEditors属性--> 
11
.        <property name=
"customEditors"
12
.            <map> 
13
.                <entry key=
"java.util.Date"
14
.                    <!-- 内部bean只供自己使用 --> 
15
.                    <bean
class
=
"com.szy.spring.util.DatePropertyEditor"
/> 
16
.                </entry> 
17
.            </map> 
18
.        </property> 
19
.    </bean> 
20
.     
21
.</beans> 
  
  
  
下面我们修改下测试代码已读取所有的配置文件
  
 
 
Java代码 
1
.ApplicationContext ctx=
new 
ClassPathXmlApplicationContext(
"application*.xml"
); 
2
.        Bean bean = (Bean)ctx.getBean(
"bean"
); 
3
.        System.out.println(bean.getDate()); 
  
  
  
最后测试,成功输出时间。
  
刚才我们在配置文件中时间的格式是
2009
-
11
-
21
,如果我们修改成
2009
/
11
/
21
呢?
  
运行报错:Unparseable date:
"2009/11/21"
  
这时我们需要修改属性编辑器类文件的格式了,很麻烦。既然spring支持注入,那么我们为什么不对格式进行注入呢?
  
修改属性编辑器类:
  
 
 
Java代码 
1
.
package 
com.szy.spring.util; 
2
3
.
import 
java.beans.PropertyEditorSupport; 
4
.
import 
java.text.SimpleDateFormat; 
5
.
import 
java.util.Date; 
6
7
.
public 
class 
DatePropertyEditor
extends 
PropertyEditorSupport 
8
.{ 
9
10
.   
private 
String format; 
11
.   
@Override 
12
.   
public 
void 
setAsText(String text)
throws 
IllegalArgumentException 
13
.    { 
14
.         
15
.        SimpleDateFormat sdf=
new 
SimpleDateFormat(format); 
16
.       
try 
17
.        { 
18
.            Date date=sdf.parse(text); 
19
.           
this
.setValue(date); 
//把转换后的值传过去 
20
.        }
catch 
(Exception e) 
21
.        { 
22
.            e.printStackTrace(); 
23
.        } 
24
.    } 
25
.   
public 
String getFormat() 
26
.    { 
27
.       
return 
format; 
28
.    } 
29
.   
public 
void 
setFormat(String format) 
30
.    { 
31
.       
this
.format = format; 
32
.    } 
33
.} 
  
  
  
同时给该类对应的bean添加属性节点
  
 
 
Xml代码 
1
.<bean
class
=
"com.szy.spring.util.DatePropertyEditor"
2
.                        <property name=
"format" 
value=
"yyyy/MM/dd"
></property> 
3
.                    </bean> 
  
  
  
下次只要我们修改配置文件即可,灵活性很大。
 
 
 
 
 
 
 
 
Spring学习笔记(
12
)----静态代理模式分析演示
--------------------------------------------
代理模式分为静态代理和动态代理。静态代理就是我们自己定义的代理类,动态代理是程序在运行时生成的代理类。
  
下面演示下静态代理类。首先我们要定义一个接口:
  
 
 
Java代码 
1
.
package 
com.szy.spring; 
2
3
.
public 
interface 
UserManager 
4
.{ 
5
.   
public 
void 
addUser(String username,String password); 
6
.   
public 
void 
deleteUser(
int 
userId); 
7
.   
public 
void 
modifyUser(
int 
userId,String username,String password); 
8
.   
public 
void 
findUser(
int 
userId); 
9
.} 
  
 
比较常见的对用户进行增删改查。
  
下面我们常见一个实现类,实现这个接口。
  
 
 
Java代码 
1
.
package 
com.szy.spring; 
2
3
.
public 
class 
UserManagerImpl
implements 
UserManager 
4
.{ 
5
6
.   
public 
void 
addUser(String username, String password) 
7
.    { 
8
.        System.out.println(
"--------UserManagerImpl.addUser()----------"
); 
9
.    } 
10
11
.   
public 
void 
deleteUser(
int 
userId) 
12
.    { 
13
.        System.out.println(
"--------UserManagerImpl.deleteUser()----------"
); 
14
.    } 
15
16
.   
public 
void 
findUser(
int 
userId) 
17
.    { 
18
.        System.out.println(
"--------UserManagerImpl.findUser()----------"
); 
19
.    } 
20
21
.   
public 
void 
modifyUser(
int 
userId, String username, String password) 
22
.    { 
23
.        System.out.println(
"--------UserManagerImpl.modifyUser()----------"
); 
24
.    } 
25
.} 
  
  
  
每个方法仅仅是输出一句话。
  
下面我们定义一个客户端类来调用这些方法。
  
 
 
Java代码 
1
.
package 
com.szy.spring; 
2
3
.
public 
class 
Client 
4
.{ 
5
.   
public 
static 
void 
main(String[] args) 
6
.    { 
7
.        UserManager userManager=
new 
UserManagerImpl(); 
8
.        userManager.addUser(
"coolszy"
,
"kuka"
); 
9
.    } 
10
.} 
  
  
  
运行正常输出我们期望的结果。
  
下面我们需要加入安全性检查,就是调用方法前我们需要进行验证,比较常见的就是权限验证,验证用户是否拥有权限,
  
比较常见的做法就是在UserManagerImpl类中定义一个检查安全性的方法:
  
 
 
Java代码 
1
.
public 
void 
checkSecurity() 
2
.    { 
3
.        System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
); 
4
.    } 
  
 
然后在每个方法中都要调用这个方法。但是这样不符合开-闭原则(Open-Closed principle,简称OCP)。因此我们可以使用代理类来实现这个功能。代理模式很显著的特征就是和目标对象的接口一致。在代理类中我们可以控制目标对象。要控制目标对象我们必须有一个目标对象的引用。为了灵活我们可以把目标对象传到方法中,而不是在方法中实例化。同时我们把安全性检查的代码也放到代理类中,在调用每个方法之前调用这个检查方法,通过代理对我们以前的类没有破坏。
  
 
 
Java代码 
1
.
package 
com.szy.spring; 
2
3
.
public 
class 
UserManagerImplProxy
implements 
UserManager 
4
.{ 
5
.   
private 
UserManager userManager; 
6
.     
7
.   
public 
UserManagerImplProxy(UserManager userManager) 
8
.    { 
9
.       
this
.userManager = userManager; 
10
.    } 
11
.   
public 
void 
addUser(String username, String password) 
12
.    { 
13
.        checkSecurity(); 
14
.       
this
.userManager.addUser(username, password); 
15
.    } 
16
.   
public 
void 
deleteUser(
int 
userId) 
17
.    { 
18
.        checkSecurity(); 
19
.       
this
.userManager.deleteUser(userId); 
20
.    } 
21
.   
public 
String findUser(
int 
userId) 
22
.    { 
23
.        checkSecurity(); 
24
.       
return 
this
.userManager.findUser(userId); 
25
.    } 
26
.   
public 
void 
modifyUser(
int 
userId, String username, String password) 
27
.    { 
28
.        checkSecurity(); 
29
.       
this
.userManager.modifyUser(userId, username, password); 
30
.    } 
31
.   
public 
void 
checkSecurity() 
32
.    { 
33
.        System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
); 
34
.    } 
35
.} 
  
  
  
下面修改客户端类。
  
 
 
Java代码 
1
.UserManager userManager=
new 
UserManagerImplProxy(
new 
UserManagerImpl()); 
2
.        userManager.addUser(
"coolszy"
,
"kuka"
); 
  
  
  
这样总的来说比较灵活。这个依赖关系是我们自己做的,我们完全可以交给spring处理。
  
按照上面的这种做法有一个缺点,如果接口中方法很多,那么我们实现每一个方法都要添加检查方法checkSecurity(),影响了我们的业务处理。采用静态代理模式我们是没法解决的,这时我们需要使用AOP思想。
  
  
 
 
 
 
Spring学习笔记(
13
)----动态代理模式分析演示
-----------------------------------------------
上一节演示的是静态代理模式,本节演示的是静态代理模式,既然是动态,那么就不存在UserManagerImplProxy类。
  
使用动态代理我们需要声明一个类SecurityHandler,这个类要实现InvocationHandler接口。
  
在类中定义一个产生动态代理的方法newProxy();同时把我们验证的代码放到这个类中。通过SecurityHandler,当我们调用方法时默认会调用SecurityHandler类invoke方法,我们在这个方法中进行安全性检查,检查通过后在调用真实的方法。需要注意的是目标对象接口中的部分方法是存在返回值的。
  
 
 
Java代码 
1
.
package 
com.szy.spring; 
2
3
.
import 
java.lang.reflect.InvocationHandler; 
4
.
import 
java.lang.reflect.Method; 
5
.
import 
java.lang.reflect.Proxy; 
6
7
.
public 
class 
SecurityHandler
implements 
InvocationHandler 
8
.{ 
9
.   
private 
Object targetObject; 
10
.     
11
.   
public 
Object newProxy(Object targetObject) 
12
.    { 
13
.       
this
.targetObject=targetObject; 
14
.       
//返回动态代理 
15
.       
return 
Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), 
16
.                                      targetObject.getClass().getInterfaces(), 
17
.                                     
this
); 
18
.    } 
19
.   
public 
Object invoke(Object proxy, Method method, Object[] args) 
20
.           
throws 
Throwable 
21
.    { 
22
.        checkSecurity(); 
23
.        Object ret=
null
24
.       
try 
25
.        { 
26
.           
//调用目标对象的真实方法 
27
.            ret=method.invoke(
this
.targetObject, args); 
28
.           
//ret接受存在的返回值,不存在返回值则为Null 
29
.        }
catch 
(Exception e) 
30
.        { 
31
.            e.printStackTrace(); 
32
.        } 
33
.       
return 
null
34
.    } 
35
.   
public 
void 
checkSecurity() 
36
.    { 
37
.        System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
); 
38
.    } 
39
.} 
  
  
  
使用这种方式维护起来相对比较好,我想进行安全性检查就进行,不想就不进行,很方便。
  
下面进行客户端调用
  
 
 
Java代码 
1
.
package 
com.szy.spring; 
2
3
.
public 
class 
Client 
4
.{ 
5
.   
public 
static 
void 
main(String[] args) 
6
.    { 
7
.        SecurityHandler handler=
new 
SecurityHandler(); 
8
.       
//创建代理对象 
9
.        UserManager userManager=(UserManager)handler.newProxy(
new 
UserManagerImpl()); 
10
.        userManager.addUser(
"coolszy"
,
"kuka"
); 
11
.    } 
12
.} 
 
 
 
 
 

转载地址:http://hsfbi.baihongyu.com/

你可能感兴趣的文章
多线程使用随机函数需要注意的一点
查看>>
getpeername,getsockname
查看>>
让我做你的下一行Code
查看>>
浅析:setsockopt()改善程序的健壮性
查看>>
关于对象赋值及返回临时对象过程中的构造与析构
查看>>
VS 2005 CRT函数的安全性增强版本
查看>>
SQL 多表联合查询
查看>>
Visual Studio 2010:C++0x新特性
查看>>
drwtsn32.exe和adplus.vbs进行dump文件抓取
查看>>
cppcheck c++静态代码检查
查看>>
CLOSE_WAIT和TIME_WAIT
查看>>
在C++中使用Lua
查看>>
在Dll中调用自身的位图资源
查看>>
IP校验和详解
查看>>
C++中使用Mongo执行count和distinct运算
查看>>
一些socket的编程经验
查看>>
socket编程中select的使用
查看>>
C++获取文件大小常用技巧分享
查看>>
未来5年大机遇:做贩卖多巴胺的超级玩家
查看>>
关于AIS编码解码的两个小问题
查看>>